Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>, Lists.newArrayList(externs, root), this); } private Map<String,Boolean> constantMap = Maps.newHashMap(); @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.NAME) { String name = n.getString(); if (n.getString().isEmpty()) { return; } boolean isConst = n.getBooleanProp(Node.IS_CONSTANT_NAME); if (checkUserDeclarations) { boolean expectedConst = false; if (NodeUtil.isConstantName(n) || compiler.getCodingConvention().isConstant(n.getString())) { expectedConst = true; } else { expectedConst = false; JSDocInfo info = null; Var var = t.getScope().getVar(n.getString()); if (var != null) { info = var.getJSDocInfo(); } if (info != null && info.isConstant()) { expectedConst = true; } else { expectedConst = false; } } if (expectedConst) { Preconditions.checkState(expectedConst == isConst, "The name " + name + " is not annotated as constant."); } else { Preconditions.checkState(expectedConst == isConst, "The name " + name + " should not be annotated as constant."); } } Boolean value = constantMap.get(name); if (value == null) { constantMap.put(name, isConst); } else { Preconditions.checkState(value.booleanValue() == isConst, "The name " + name + " is not consistently annotated as " + "constant."); } } } } /** * Simplify the AST: * - VAR declarations split, so they represent exactly one child * declaration. * - WHILEs are converted to FORs * - FOR loop are initializers are moved out of the FOR structure * - LABEL node of children other than LABEL, BLOCK, WHILE, FOR, or DO are * moved into a block. */ static class NormalizeStatements implements Callback { private final AbstractCompiler compiler; private final boolean assertOnChange; NormalizeStatements(AbstractCompiler compiler, boolean assertOnChange

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>) { this.compiler = compiler; this.assertOnChange = assertOnChange; } private void reportCodeChange(String changeDescription) { if (assertOnChange) { throw new IllegalStateException( "Normalize constraints violated:\n" + changeDescription); } compiler.reportCodeChange(); } @Override public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { doStatementNormalizations(t, n, parent); return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.WHILE: if (CONVERT_WHILE_TO_FOR) { Node expr = n.getFirstChild(); n.setType(Token.FOR); n.addChildBefore(new Node(Token.EMPTY), expr); n.addChildAfter(new Node(Token.EMPTY), expr); reportCodeChange("WHILE node"); } break; } } /** * Do normalizations that introduce new siblings or parents. */ private void doStatementNormalizations( NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.LABEL) { normalizeLabels(n); } // Only inspect the children of SCRIPTs, BLOCKs and LABELs, as all these // are the only legal place for VARs and FOR statements. if (NodeUtil.isStatementBlock(n) || n.getType() == Token.LABEL) { extractForInitializer(n, null, null); } // Only inspect the children of SCRIPTs, BLOCKs, as all these // are the only legal place for VARs. if (NodeUtil.isStatementBlock(n)) { splitVarDeclarations(n); } if (n.getType() == Token.FUNCTION) { moveNamedFunctions(n.getLastChild()); } } // TODO(johnlenz): Move this to NodeTypeNormalizer once the unit tests are // fixed. /** * Limit the number of special cases where LABELs need to be handled. Only * BLOCK and loops are allowed to be labeled. Loop labels must remain in * place as the named continues are not allowed for labeled blocks. */ private void normalizeLabels(Node n)

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { Preconditions.checkArgument(n.getType() == Token.LABEL); Node last = n.getLastChild(); switch (last.getType()) { case Token.LABEL: case Token.BLOCK: case Token.FOR: case Token.WHILE: case Token.DO: return; default: Node block = new Node(Token.BLOCK); n.replaceChild(last, block); block.addChildToFront(last); reportCodeChange("LABEL normalization"); return; } } /** * Bring the initializers out of FOR loops. These need to be placed * before any associated LABEL nodes. This needs to be done from the top * level label first so this is called as a pre-order callback (from * shouldTraverse). * * @param n The node to inspect. * @param before The node to insert the initializer before. * @param beforeParent The parent of the node before which the initializer * will be inserted. */ private void extractForInitializer( Node n, Node before, Node beforeParent) { for (Node next, c = n.getFirstChild(); c != null; c = next) { next = c.getNext(); Node insertBefore = (before == null) ? c : before; Node insertBeforeParent = (before == null) ? n : beforeParent; switch (c.getType()) { case Token.LABEL: extractForInitializer(c, insertBefore, insertBeforeParent); break; case Token.FOR: if (!NodeUtil.isForIn(c) && c.getFirstChild().getType() != Token.EMPTY) { Node init = c.getFirstChild(); c.replaceChild(init, new Node(Token.EMPTY)); Node newStatement; // Only VAR statements, and expressions are allowed, // but are handled differently. if (init.getType() == Token.VAR) { newStatement = init; } else { newStatement = NodeUtil.newExpr(init); } insertBeforeParent.addChildBefore(newStatement, insertBefore); reportCodeChange("FOR initializer"); } break; } } } /** * Split a var node such as: * var a, b; * into individual statements:

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * var a; * var b; * @param n The whose children we should inspect. */ private void splitVarDeclarations(Node n) { for (Node next, c = n.getFirstChild(); c != null; c = next) { next = c.getNext(); if (c.getType() == Token.VAR) { if (assertOnChange && !c.hasChildren()) { throw new IllegalStateException("Empty VAR node."); } while (c.getFirstChild() != c.getLastChild()) { Node name = c.getFirstChild(); c.removeChild(name); Node newVar = new Node( Token.VAR, name, n.getLineno(), n.getCharno()); n.addChildBefore(newVar, c); reportCodeChange("VAR with multiple children"); } } } } /** * Move all the functions that are valid at the execution of the first * statement of the function to the beginning of the function definition. */ private void moveNamedFunctions(Node functionBody) { Preconditions.checkState( functionBody.getParent().getType() == Token.FUNCTION); Node previous = null; Node current = functionBody.getFirstChild(); // Skip any declarations at the beginning of the function body, they // are already in the right place. while (current != null && NodeUtil.isFunctionDeclaration(current)) { previous = current; current = current.getNext(); } // Find any remaining declarations and move them. Node insertAfter = previous; while (current != null) { // Save off the next node as the current node maybe removed. Node next = current.getNext(); if (NodeUtil.isFunctionDeclaration(current)) { // Remove the declaration from the body. Preconditions.checkNotNull(previous); functionBody.removeChildAfter(previous); // Readd the function at the top of the function body (after any // previous declarations). insertAfter = addToFront(functionBody, current, insertAfter); reportCodeChange("Move function declaration not at top of function"); } else { // Update the previous only if the current node hasn't been moved. previous = current; } current = next; } } /** * @param after The child node to insert the newChild after,

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>, as the next node of interest is the parent's // next sibling. // if (n.hasChildren()) { // The var is being initialize, preserve the new value. parent.removeChild(n); // Convert "var name = value" to "name = value" Node value = n.getFirstChild(); n.removeChild(value); Node replacement = new Node(Token.ASSIGN, n, value); gramps.replaceChild(parent, new Node(Token.EXPR_RESULT, replacement)); } else { // It is an empty reference remove it. if (NodeUtil.isStatementBlock(gramps)) { gramps.removeChild(parent); } else if (gramps.getType() == Token.FOR) { // This is the "for (var a in b)..." case. We don't need to worry // about initializers in "for (var a;;)..." as those are moved out // as part of the other normalizations. parent.removeChild(n); gramps.replaceChild(parent, n); } else { Preconditions.checkState(gramps.getType() == Token.LABEL); gramps.replaceChild(parent, new Node(Token.EMPTY)); } } reportCodeChange("Duplicate VAR declaration"); } } } /** * A simple class that causes scope to be created. */ private final class ScopeTicklingCallback implements NodeTraversal.ScopedCallback { @Override public void enterScope(NodeTraversal t) { // Cause the scope to be created, which will cause duplicate // to be found. t.getScope(); } @Override public void exitScope(NodeTraversal t) { // Nothing to do. } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { // Nothing to do. } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>name); } nameStack.push(renamer); } break; case Token.CATCH: { Renamer renamer = nameStack.peek().forChildScope(); String name = n.getFirstChild().getString(); renamer.addDeclaredName(name); nameStack.push(renamer); } break; } return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: String newName = getReplacementName(n.getString()); if (newName != null) { Renamer renamer = nameStack.peek(); if (renamer.stripConstIfReplaced()) { // TODO(johnlenz): Do we need to do anything about the javadoc? n.removeProp(Node.IS_CONSTANT_NAME); } n.setString(newName); t.getCompiler().reportCodeChange(); } break; case Token.FUNCTION: // Remove function recursive name (if any). nameStack.pop(); break; case Token.CATCH: // Remove catch except name from the stack of names. nameStack.pop(); break; } } /** * Walks the stack of name maps and finds the replacement name for the * current scope. */ private String getReplacementName(String oldName) { for (Renamer names : nameStack) { String newName = names.getReplacementName(oldName); if (newName != null) { return newName; } } return null; } /** * Traverses the current scope and collects declared names. Does not * decent into functions or add CATCH exceptions. */ private void findDeclaredNames(Node n, Node parent, Renamer renamer) { // Do a shallow traversal, so don't traverse into function declarations, // except for the name of the function itself. if (parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild()) { if (NodeUtil.isVarDeclaration(n)) { renamer.addDeclaredName(n.getString()); } else if (NodeUtil.isFunctionDeclaration(n)) { Node name

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Maps; import com.google.javascript.rhino.FunctionNode; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * NodeUtil contains utilities that get properties from the Node object. * * * */ public final class NodeUtil { // TODO(user): Eliminate this class and make all of the static methods // instance methods of com.google.javascript.rhino.Node. /** the set of builtin constructors that don't have side effects. */ private static final Set<String> CONSTRUCTORS_WITHOUT_SIDE_EFFECTS = new HashSet<String>(Arrays.asList( "Array", "Date", "Error", "Object", "RegExp", "XMLHttpRequest")); public static final String CONSTANT_MARKER = "$$constant"; // Utility class; do not instantiate. private NodeUtil() {} /** * Gets the boolean value of a node that represents a literal

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>. This method * effectively emulates the <code>Boolean()</code> JavaScript cast function. * * @throws IllegalArgumentException If {@code n} is not a literal value */ static boolean getBooleanValue(Node n) { switch (n.getType()) { case Token.STRING: return n.getString().length() > 0; case Token.NUMBER: return n.getDouble() != 0; case Token.NULL: case Token.FALSE: case Token.VOID: return false; case Token.NAME: String name = n.getString(); if ("undefined".equals(name) || "NaN".equals(name)) { // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return false; } else if ("Infinity".equals(name)) { return true; } break; case Token.TRUE: case Token.ARRAYLIT: case Token.OBJECTLIT: case Token.REGEXP: return true; } throw new IllegalArgumentException("Non-literal value: " + n); } /** * Gets the value of a node as a String, or null if it cannot be converted. * When it returns a non-null String, this method effectively emulates the * <code>String()</code> JavaScript cast function. */ static String getStringValue(Node n) { // TODO(user): Convert constant array, object, and regex literals as well. switch (n.getType()) { case Token.NAME: case Token.STRING: return n.getString(); case Token.NUMBER: double value = n.getDouble(); long longValue = (long) value; // Return "1" instead of "1.0" if (longValue == value) { return Long.toString(longValue); } else { return Double.toString(n.getDouble()); } case Token.FALSE: case Token.TRUE: case Token.NULL: return Node.tokenToName(n.getType()); case Token.VOID: return "undefined"; } return null; } /** * Gets the function's name. This method recognizes five forms: * <ul> * <li>{@code function name() ...}</li>

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * <li>{@code var name = function() ...}</li> * <li>{@code qualified.name = function() ...}</li> * <li>{@code var name2 = function name1() ...}</li> * <li>{@code qualified.name2 = function name1() ...}</li> * </ul> * In two last cases with named anonymous functions, the second name is * returned (the variable of qualified name). * * @param n a node whose type is {@link Token#FUNCTION} * @param parent {@code n}'s parent (never {@code null}) * @return the function's name, or {@code null} if it has no name */ static String getFunctionName(Node n, Node parent) { String name = n.getFirstChild().getString(); switch (parent.getType()) { case Token.NAME: // var name = function() ... // var name2 = function name1() ... return parent.getString(); case Token.ASSIGN: // qualified.name = function() ... // qualified.name2 = function name1() ... return parent.getFirstChild().getQualifiedName(); default: // function name() ... return name != null && name.length() != 0 ? name : null; } } /** * Returns true if this is an immutable value. */ static boolean isImmutableValue(Node n) { switch (n.getType()) { case Token.STRING: case Token.NUMBER: case Token.NULL: case Token.TRUE: case Token.FALSE: case Token.VOID: return true; case Token.NEG: return isImmutableValue(n.getFirstChild()); case Token.NAME: String name = n.getString(); // We assume here that programs don't change the value of the keyword // undefined to something other than the value undefined. return "undefined".equals(name) || "Infinity".equals(name) || "NaN".equals(name); } return false; } /** * Returns true if this is a literal value. We define a literal value * as any node that evaluates to the same thing regardless of when or * where it is evaluated. So /xyz/ and [3, 5] are literals, but * function()

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { return a; } is not. */ static boolean isLiteralValue(Node n) { // TODO(nicksantos): Refine this function to catch more literals. switch (n.getType()) { case Token.ARRAYLIT: case Token.OBJECTLIT: case Token.REGEXP: // Return true only if all children are const. for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { if (!isLiteralValue(child)) { return false; } } return true; default: return isImmutableValue(n); } } /** * Determines whether the given value may be assigned to a define. * * @param val The value being assigned. * @param defines The list of names of existing defines. */ static boolean isValidDefineValue(Node val, Set<String> defines) { switch (val.getType()) { case Token.STRING: case Token.NUMBER: case Token.TRUE: case Token.FALSE: return true; // Single operators are valid if the child is valid. case Token.BITAND: case Token.BITNOT: case Token.BITOR: case Token.BITXOR: case Token.NOT: case Token.NEG: return isValidDefineValue(val.getFirstChild(), defines); // Names are valid if and only if they are defines themselves. case Token.NAME: case Token.GETPROP: if (val.isQualifiedName()) { return defines.contains(val.getQualifiedName()); } } return false; } /** * Returns whether this a BLOCK node with no children. * * @param block The node. */ static boolean isEmptyBlock(Node block) { if (block.getType() != Token.BLOCK) { return false; } for (Node n = block.getFirstChild(); n != null; n = n.getNext()) { if (n.getType() != Token.EMPTY) { return false; } } return true; } /** * A "simple" operator is one whose children are expressions, * has no direct side-effects (unlike '+='), and has no * conditional aspects (unlike '||'). */ static boolean is

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> know to be safe switch (n.getType()) { // other side-effect free statements and expressions case Token.AND: case Token.BLOCK: case Token.EXPR_RESULT: case Token.HOOK: case Token.IF: case Token.IN: case Token.LP: case Token.NUMBER: case Token.OR: case Token.THIS: case Token.TRUE: case Token.FALSE: case Token.NULL: case Token.STRING: case Token.SWITCH: case Token.TRY: case Token.EMPTY: break; // Throws are by definition side effects case Token.THROW: return true; case Token.OBJECTLIT: case Token.ARRAYLIT: case Token.REGEXP: if (checkForNewObjects) { return true; } break; case Token.VAR: // empty var statement (no declaration) case Token.NAME: // variable by itself if (n.getFirstChild() != null) return true; break; case Token.FUNCTION: // Anonymous functions don't have side-effects, but named ones // change the namespace. Therefore, we check if the function has // a name. Either way, we don't need to check the children, since // they aren't executed at declaration time. // return !isFunctionAnonymous(n); case Token.NEW: { if (checkForNewObjects) { return true; } // calls to constructors that have no side effects have the // no side effect property set. if (n.isNoSideEffectsCall()) { break; } // certain constructors are certified side effect free Node constructor = n.getFirstChild(); if (Token.NAME == constructor.getType()) { String className = constructor.getString(); if (CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(className)) { // loop below will see if the constructor parameters have // side-effects break; } } else { // the constructor could also be an expression like // new (useArray ? Object : Array)(); } } return true; case Token.CALL: // calls to functions that have no side effects have the no // side effect property set. if (n.isNoSide

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>EffectsCall()) { // loop below will see if the function parameters have // side-effects break; } return true; default: if (isSimpleOperatorType(n.getType())) break; if (isAssignmentOp(n)) { // Assignments will have side effects if // a) The RHS has side effects, or // b) The LHS has side effects, or // c) A name on the LHS will exist beyond the life of this statement. if (checkForStateChangeHelper( n.getFirstChild(), checkForNewObjects) || checkForStateChangeHelper( n.getLastChild(), checkForNewObjects)) { return true; } Node current = n.getFirstChild(); for (; current.getType() == Token.GETPROP || current.getType() == Token.GETELEM; current = current.getFirstChild()) { } return !(isLiteralValue(current) || current.getType() == Token.FUNCTION); } return true; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (checkForStateChangeHelper(c, checkForNewObjects)) { return true; } } return false; } /** * Do calls to this constructor have side effects? * * @param callNode - construtor call node */ static boolean constructorCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.NEW, "Expected NEW node, got " + Token.name(callNode.getType())); if (callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); if (nameNode.getType() == Token.NAME && CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(nameNode.getString())) { return false; } return true; } /** * Returns true if calls to this function have side effects. * * @param callNode - function call node */ static boolean functionCallHasSideEffects(Node callNode) { Preconditions.checkArgument( callNode.getType() == Token.CALL, "Expected CALL node, got " + Token.name(callNode.getType())); if (

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>callNode.isNoSideEffectsCall()) { return false; } Node nameNode = callNode.getFirstChild(); // Built-in functions with no side effects. if (nameNode.getType() == Token.NAME) { String name = nameNode.getString(); if (name.equals("String")) { return false; } } // Functions in the "Math" namespace have no side effects. if (nameNode.getType() == Token.GETPROP && nameNode.getFirstChild().getType() == Token.NAME) { String namespaceName = nameNode.getFirstChild().getString(); if (namespaceName.equals("Math")) { return false; } } return true; } /** * Returns true if the current node's type implies side effects. * * This is a non-recursive version of the may have side effects * check; used to check wherever the current node's type is one of * the reason's why a subtree has side effects. */ static boolean nodeTypeMayHaveSideEffects(Node n) { if (NodeUtil.isAssignmentOp(n)) { return true; } switch(n.getType()) { case Token.CALL: case Token.DELPROP: case Token.NEW: case Token.DEC: case Token.INC: case Token.THROW: return true; case Token.NAME: // A variable definition. return n.hasChildren(); default: return false; } } /** * @return Whether the tree can be affected by side-effects or * has side-effects. */ static boolean canBeSideEffected(Node n) { Set<String> emptySet = Collections.emptySet(); return canBeSideEffected(n, emptySet); } /** * @param knownConstants A set of names known to be constant value at * node 'n' (such as locals that are last written before n can execute). * @return Whether the tree can be affected by side-effects or * has side-effects. */ static boolean canBeSideEffected(Node n, Set<String> knownConstants) { switch (n.getType()) { case Token.CALL: case Token.NEW: // Function calls or

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> constructor can reference changed values. // TODO(johnlenz): Add some mechanism for determining that functions // are unaffected by side effects. return true; case Token.NAME: // Non-constant names values may have been changed. return !NodeUtil.isConstantName(n) && !knownConstants.contains(n.getString()); // Properties on constant NAMEs can still be side-effected. case Token.GETPROP: case Token.GETELEM: return true; } for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (canBeSideEffected(c, knownConstants)) { return true; } } return false; } /* * 0 comma , * 1 assignment = += -= *= /= %= <<= >>= >>>= &= ^= |= * 2 conditional ?: * 3 logical-or || * 4 logical-and && * 5 bitwise-or | * 6 bitwise-xor ^ * 7 bitwise-and & * 8 equality == != * 9 relational < <= > >= * 10 bitwise shift << >> >>> * 11 addition/subtraction + - * 12 multiply/divide * / % * 13 negation/increment ! ~ - ++ -- * 14 call, member () [] . */ static int precedence(int type) { switch (type) { case Token.COMMA: return 0; case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN: return 1; case Token.HOOK: return 2; // ?: operator case Token.OR: return 3; case Token.AND: return 4; case Token.BITOR: return 5; case Token.BITXOR: return 6; case Token.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> /** * Is this a GETPROP node? */ static boolean isGetProp(Node n) { return n.getType() == Token.GETPROP; } /** * Is this a NAME node? */ static boolean isName(Node n) { return n.getType() == Token.NAME; } /** * Is this a NEW node? */ static boolean isNew(Node n) { return n.getType() == Token.NEW; } /** * Is this a VAR node? */ static boolean isVar(Node n) { return n.getType() == Token.VAR; } /** * Is this node the name of a variable being declared? * * @param n The node * @return True if {@code n} is NAME and {@code parent} is VAR */ static boolean isVarDeclaration(Node n) { // There is no need to verify that parent != null because a NAME node // always has a parent in a valid parse tree. return n.getType() == Token.NAME && n.getParent().getType() == Token.VAR; } /** * For an assignment or variable declaration get the assigned value. * @return The value node representing the new value. */ static Node getAssignedValue(Node n) { Preconditions.checkState(isName(n)); Node parent = n.getParent(); if (isVar(parent)) { return n.getFirstChild(); } else if (isAssign(parent) && parent.getFirstChild() == n) { return n.getNext(); } else { return null; } } /** * Is this a STRING node? */ static boolean isString(Node n) { return n.getType() == Token.STRING; } /** * Is this node an assignment expression statement? * * @param n The node * @return True if {@code n} is EXPR_RESULT and {@code n}'s * first child is ASSIGN */ static boolean isExprAssign(Node n) { return n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN; } /** * Is this an ASSIGN node? */ static boolean isAssign(Node

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>); Node parent = block.getParent(); // Try to remove the block if its parent is a block/script or if its // parent is label and it has exactly one child. if (NodeUtil.isStatementBlock(parent)) { Node previous = block; while (block.hasChildren()) { Node child = block.removeFirstChild(); parent.addChildAfter(child, previous); previous = child; } parent.removeChild(block); return true; } else if (parent.getType() == Token.LABEL && block.hasOneChild()) { parent.replaceChild(block, block.removeFirstChild()); return true; } else { return false; } } /** * Is this a CALL node? */ static boolean isCall(Node n) { return n.getType() == Token.CALL; } /** * Is this a FUNCTION node? */ static boolean isFunction(Node n) { return n.getType() == Token.FUNCTION; } /** * Return a BLOCK node for the given FUNCTION node. */ static Node getFunctionBody(Node fn) { Preconditions.checkArgument(isFunction(fn)); return fn.getLastChild(); } /** * Is this a THIS node? */ static boolean isThis(Node node) { return node.getType() == Token.THIS; } /** * Is this node or any of its children a CALL? */ static boolean containsCall(Node n) { return containsType(n, Token.CALL); } /** * Is this node a function declaration? A function declaration is a function * that has a name that is added to the current scope (i.e. a function that * is not anonymous; see {@link #isFunctionAnonymous}). */ static boolean isFunctionDeclaration(Node n) { return n.getType() == Token.FUNCTION && !isFunctionAnonymous(n); } /** * Is this node a hoisted function declaration? A function declaration in the * scope root is hoisted to the top of the scope. * See {@link #isFunctionDeclaration}). */ static boolean isHoistedFunctionDeclaration(Node n) { return NodeUtil.isFunctionDeclaration(n) && (n.getParent().getType() == Token.SCRIPT

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> || n.getParent().getParent().getType() == Token.FUNCTION); } /** * Is this node an anonymous function? An anonymous function is one that has * either no name or a name that is not added to the current scope (see * {@link #isFunctionAnonymous}). */ static boolean isAnonymousFunction(Node n) { return n.getType() == Token.FUNCTION && isFunctionAnonymous(n); } /** * Is a FUNCTION node an anonymous function? An anonymous function is one that * has either no name or a name that is not added to the current scope. * * <p>Some examples of anonymous functions: * <pre> * function () {} * (function f() {})() * [ function f() {} ] * var f = function f() {}; * for (function f() {};;) {} * </pre> * * <p>Some examples of functions that are <em>not</em> anonymous: * <pre> * function f() {} * if (x); else function f() {} * for (;;) { function f() {} } * </pre> * * @param n A FUNCTION node * @return Whether n is an anonymous function */ static boolean isFunctionAnonymous(Node n) { return !isStatement(n); } /** * Determines if a function takes a variable number of arguments by * looking for references to the "arguments" var_args object. */ static boolean isVarArgsFunction(Node function) { Preconditions.checkArgument(isFunction(function)); return NodeUtil.isNameReferenced( function.getLastChild(), "arguments", Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); } /** * @return Whether node is a call to methodName. * a.f(...) * a['f'](...) */ static boolean isObjectCallMethod(Node callNode, String methodName) { if (callNode.getType() == Token.CALL) { Node functionIndentifyingExpression = callNode.getFirstChild(); if (NodeUtil.isGet(functionIndentifyingExpression)) { Node last = functionIndentifyingExpression.getLastChild(); if (last != null && last.getType() == Token.STRING) { String propName

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> = last.getString(); return (propName.equals(methodName)); } } } return false; } /** * @return Whether the callNode represents an expression in the form of: * x.call(...) * x['call'](...) */ static boolean isFunctionObjectCall(Node callNode) { return isObjectCallMethod(callNode, "call"); } /** * @return Whether the callNode represents an expression in the form of: * x.apply(...) * x['apply'](...) */ static boolean isFunctionObjectApply(Node callNode) { return isObjectCallMethod(callNode, "apply"); } /** * @return Whether the callNode represents an expression in the form of: * x.call(...) * x['call'](...) * where x is a NAME node. */ static boolean isSimpleFunctionObjectCall(Node callNode) { if (isFunctionObjectCall(callNode)) { if (callNode.getFirstChild().getFirstChild().getType() == Token.NAME) { return true; } } return false; } /** * Determines whether this node is strictly on the left hand side of an assign * or var initialization. Notably, this does not include all L-values, only * statements where the node is used only as an L-value. * * @param n The node * @param parent Parent of the node * @return True if n is the left hand of an assign */ static boolean isLhs(Node n, Node parent) { return (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n) || parent.getType() == Token.VAR; } /** * Determines whether a node represents an object literal key * (e.g. key1 in {key1: value1, key2: value2}). * * @param node A node * @param parent The node's parent */ static boolean isObjectLitKey(Node node, Node parent) { if (node.getType() == Token.STRING && parent.getType() == Token.OBJECTLIT) { int index = 0; for (Node current = parent.getFirstChild(); current != null; current =

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> current.getNext()) { if (current == node) { return index % 2 == 0; } index++; } } return false; } /** * Converts an operator's token value (see {@link Token}) to a string * representation. * * @param operator the operator's token value to convert * @return the string representation or {@code null} if the token value is * not an operator */ static String opToStr(int operator) { switch (operator) { case Token.BITOR: return "|"; case Token.OR: return "||"; case Token.BITXOR: return "^"; case Token.AND: return "&&"; case Token.BITAND: return "&"; case Token.SHEQ: return "==="; case Token.EQ: return "=="; case Token.NOT: return "!"; case Token.NE: return "!="; case Token.SHNE: return "!=="; case Token.LSH: return "<<"; case Token.IN: return "in"; case Token.LE: return "<="; case Token.LT: return "<"; case Token.URSH: return ">>>"; case Token.RSH: return ">>"; case Token.GE: return ">="; case Token.GT: return ">"; case Token.MUL: return "*"; case Token.DIV: return "/"; case Token.MOD: return "%"; case Token.BITNOT: return "~"; case Token.ADD: return "+"; case Token.SUB: return "-"; case Token.POS: return "+"; case Token.NEG: return "-"; case Token.ASSIGN: return "="; case Token.ASSIGN_BITOR: return "|="; case Token.ASSIGN_BITXOR: return "^="; case Token.ASSIGN_BITAND: return "&="; case Token.ASSIGN_LSH: return "<<="; case Token.ASSIGN_RSH: return ">>="; case Token.ASSIGN_URSH: return ">>>="; case Token.ASSIGN_ADD: return "+="; case Token.ASSIGN_SUB: return "-="; case Token.ASSIGN_MUL: return "*="; case Token.ASSIGN_DIV: return "/=";

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> case Token.ASSIGN_MOD: return "%="; case Token.VOID: return "void"; case Token.TYPEOF: return "typeof"; case Token.INSTANCEOF: return "instanceof"; default: return null; } } /** * Converts an operator's token value (see {@link Token}) to a string * representation or fails. * * @param operator the operator's token value to convert * @return the string representation * @throws Error if the token value is not an operator */ static String opToStrNoFail(int operator) { String res = opToStr(operator); if (res == null) { throw new Error("Unknown op " + operator + ": " + Token.name(operator)); } return res; } /** * @return true if n or any of its children are of the specified type. * Does not traverse into functions. */ static boolean containsTypeInOuterScope(Node node, int type) { return containsType(node, type, Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); } /** * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type, Predicate<Node> traverseChildrenPred) { return has(node, new MatchNodeType(type), traverseChildrenPred); } /** * @return true if n or any of its children are of the specified type */ static boolean containsType(Node node, int type) { return containsType(node, type, Predicates.<Node>alwaysTrue()); } /** * Given a node tree, finds all the VAR declarations in that tree that are * not in an inner scope. Then adds a new VAR node at the top of the current * scope that redeclares them, if necessary. */ static void redeclareVarsInsideBranch(Node branch) { Collection<Node> vars = getVarsDeclaredInBranch(branch); if (vars.isEmpty()) { return; } Node parent = getAddingRoot(branch); for (Node nameNode : vars) { Node var = new Node( Token.VAR, Node.newString(Token.NAME, nameNode.getString()));

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> copyNameAnnotations(nameNode, var.getFirstChild()); parent.addChildToFront(var); } } /** * Copy any annotations that follow a named value. * @param source * @param destination */ static void copyNameAnnotations(Node source, Node destination) { if (source.getBooleanProp(Node.IS_CONSTANT_NAME)) { destination.putBooleanProp(Node.IS_CONSTANT_NAME, true); } } /** * Gets a Node at the top of the current scope where we can add new var * declarations as children. */ private static Node getAddingRoot(Node n) { Node addingRoot = null; Node ancestor = n; while (null != (ancestor = ancestor.getParent())) { int type = ancestor.getType(); if (type == Token.SCRIPT) { addingRoot = ancestor; break; } else if (type == Token.FUNCTION) { addingRoot = ancestor.getLastChild(); break; } } // make sure that the adding root looks ok Preconditions.checkState(addingRoot.getType() == Token.BLOCK || addingRoot.getType() == Token.SCRIPT); Preconditions.checkState(addingRoot.getFirstChild() == null || addingRoot.getFirstChild().getType() != Token.SCRIPT); return addingRoot; } /** Creates function name(params_0, ..., params_n) { body }. */ public static FunctionNode newFunctionNode(String name, List<Node> params, Node body, int lineno, int charno) { Node parameterParen = new Node(Token.LP, lineno, charno); for (Node param : params) { parameterParen.addChildToBack(param); } FunctionNode function = new FunctionNode(name, lineno, charno); function.addChildrenToBack( Node.newString(Token.NAME, name, lineno, charno)); function.addChildToBack(parameterParen); function.addChildToBack(body); return function; } /** * Creates a node representing a qualified name. * * @param name A qualified name (e.g. "foo" or "foo.bar.baz") * @param lineno The source line offset. * @param charno The source character offset from start

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> c = s.charAt(index); if (c > LARGEST_BASIC_LATIN) { return false; } } return true; } /** * Determines whether the given name can appear on the right side of * the dot operator. Many properties (like reserved words) cannot. */ static boolean isValidPropertyName(String name) { return TokenStream.isJSIdentifier(name) && !TokenStream.isKeyword(name) && // no Unicode escaped characters - some browsers are less tolerant // of Unicode characters that might be valid according to the // language spec. // Note that by this point, unicode escapes have been converted // to UTF-16 characters, so we're only searching for character // values, not escapes. NodeUtil.isLatin(name); } private static class VarCollector implements Visitor { final Map<String, Node> vars = Maps.newLinkedHashMap(); public void visit(Node n) { if (n.getType() == Token.NAME) { Node parent = n.getParent(); if (parent != null && parent.getType() == Token.VAR) { String name = n.getString(); if (!vars.containsKey(name)) { vars.put(name, n); } } } } } /** * Retrieves vars declared in the current node tree, excluding descent scopes. */ public static Collection<Node> getVarsDeclaredInBranch(Node root) { VarCollector collector = new VarCollector(); visitPreOrder( root, collector, Predicates.<Node>not(new NodeUtil.MatchNodeType(Token.FUNCTION))); return collector.vars.values(); } /** * @return {@code true} if the node an assignment to a prototype property of * some constructor. */ static boolean isPrototypePropertyDeclaration(Node n) { if (!NodeUtil.isExprAssign(n)) { return false; } return isPrototypeProperty(n.getFirstChild().getFirstChild()); } static boolean isPrototypeProperty(Node n) { String lhsString = n.getQualifiedName(); if (lhsString == null) { return false; } int prototypeIdx = lhsString.indexOf(".prototype."); return prototypeIdx != -1;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } /** * @return The class name part of a qualified prototype name. */ static Node getPrototypeClassName(Node qName) { Node cur = qName; while (isGetProp(cur)) { if (cur.getLastChild().getString().equals("prototype")) { return cur.getFirstChild(); } else { cur = cur.getFirstChild(); } } return null; } /** * @return The string property name part of a qualified prototype name. */ static String getPrototypePropertyName(Node qName) { String qNameStr = qName.getQualifiedName(); int prototypeIdx = qNameStr.lastIndexOf(".prototype."); int memberIndex = prototypeIdx + ".prototype".length() + 1; return qNameStr.substring(memberIndex); } /** * Create a node for an empty result expression: * "void 0" */ static Node newUndefinedNode() { // TODO(johnlenz): Why this instead of the more common "undefined"? return new Node(Token.VOID, Node.newNumber(0)); } /** * Create a VAR node containing the given name and initial value expression. */ static Node newVarNode(String name, Node value) { Node nodeName = Node.newString(Token.NAME, name); if (value != null) { nodeName.addChildrenToBack(value); } Node var = new Node(Token.VAR, nodeName); return var; } /** * A predicate for matching name nodes with the specified node. */ private static class MatchNameNode implements Predicate<Node>{ final String name; MatchNameNode(String name){ this.name = name; } public boolean apply(Node n) { return n.getType() == Token.NAME && n.getString().equals(name); } } /** * A predicate for matching nodes with the specified type. */ static class MatchNodeType implements Predicate<Node>{ final int type; MatchNodeType(int type){ this.type = type; } public boolean apply(Node n) { return n.getType() == type; } } /** * Whether a Node type is within the node tree. */ static boolean isNodeTypeReferenced(

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> X="continue";id=Id_continue; break L; case 'd': X="debugger";id=Id_debugger; break L; case 'f': X="function";id=Id_function; break L; case 'v': X="volatile";id=Id_volatile; break L; } break L; case 9: c=s.charAt(0); if (c=='i') { X="interface";id=Id_interface; } else if (c=='p') { X="protected";id=Id_protected; } else if (c=='t') { X="transient";id=Id_transient; } break L; case 10: c=s.charAt(1); if (c=='m') { X="implements";id=Id_implements; } else if (c=='n') { X="instanceof";id=Id_instanceof; } break L; case 12: X="synchronized";id=Id_synchronized; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# // #/string_id_map# if (id == 0) { return Token.EOF; } return id & 0xff; } public static boolean isJSIdentifier(String s) { int length = s.length(); if (length == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i=1; i<length; i++) { char c = s.charAt(i); if (!Character.isJavaIdentifierPart(c)) { if (c == '\\') { if (! ((i + 5) < length) && (s.charAt(i + 1) == 'u') && 0 <= Kit.xDigitToInt(s.charAt(i + 2), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 3), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 4), 0) && 0 <= Kit.xDigitToInt(s.charAt(i + 5), 0

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> path to the Jar. private String originalPath = null; // Remember the offset for the previous line query. If the next line // is after this point, we can start scanning at the previous offset rather // than starting at the beginning of the file. private int lastOffset; private int lastLine; private String code = null; /** * Construct a new abstract source file. * * @param fileName The file name of the source file. It does not necessarily * need to correspond to a real path. But it should be unique. Will * appear in warning messages emitted by the compiler. */ SourceFile(String fileName) { this.fileName = fileName; // Starting point: offset 0 is at line 1. this.lastOffset = 0; this.lastLine = 1; } ////////////////////////////////////////////////////////////////////////////// // Implementation /** * Gets all the code in this source file. * @throws IOException */ public String getCode() throws IOException { return code; } @VisibleForTesting String getCodeNoCache() { return code; } private void setCode(String sourceCode) { code = sourceCode; } public String getOriginalPath() { return originalPath != null ? originalPath : fileName; } public void setOriginalPath(String originalPath) { this.originalPath = originalPath; } // For SourceFile types which cache source code that can be regenerated // easily, flush the cache. We maintain the cache mostly to speed up // generating source when displaying error messages, so dumping the file // contents after the compile is a fine thing to do. public void clearCachedSource() { // By default, do nothing. Not all kinds of SourceFiles can regenerate // code. } /** Returns a unique name for the source file. */ public String getName() { return fileName; } /** * Gets the source line for the indicated line number. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String get

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(String sourceName) { this.sourceName = sourceName; } public final int getEncodedSourceStart() { return encodedSourceStart; } public final int getEncodedSourceEnd() { return encodedSourceEnd; } public final void setEncodedSourceBounds(int start, int end) { this.encodedSourceStart = start; this.encodedSourceEnd = end; } public final int getBaseLineno() { return baseLineno; } public final void setBaseLineno(int lineno) { // One time action if (lineno < 0 || baseLineno >= 0) Kit.codeBug(); baseLineno = lineno; } public final int getEndLineno() { return endLineno; } public final void setEndLineno(int lineno) { // One time action if (lineno < 0 || endLineno >= 0) Kit.codeBug(); endLineno = lineno; } public final int getFunctionCount() { if (functions == null) { return 0; } return functions.size(); } public final FunctionNode getFunctionNode(int i) { return (FunctionNode)functions.get(i); } public final int addFunction(FunctionNode fnNode) { if (fnNode == null) Kit.codeBug(); if (functions == null) { functions = new ObjArray(); } functions.add(fnNode); return functions.size() - 1; } public final int getRegexpCount() { if (regexps == null) { return 0; } return regexps.size() / 2; } public final String getRegexpString(int index) { return (String)regexps.get(index * 2); } public final String getRegexpFlags(int index) { return (String)regexps.get(index * 2 + 1); } public final int addRegexp(String string, String flags) { if (string == null) Kit.codeBug(); if (regexps == null) { regexps = new ObjArray(); } regexps.add(string); regexps.add(flags); return regexps.size() / 2 - 1; } public final boolean hasParamOrVar

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(String name) { return itsVariableNames.has(name); } public final int getParamOrVarIndex(String name) { return itsVariableNames.get(name, -1); } public final String getParamOrVarName(int index) { return (String)itsVariables.get(index); } public final int getParamCount() { return varStart; } public final int getParamAndVarCount() { return itsVariables.size(); } public final String[] getParamAndVarNames() { int N = itsVariables.size(); if (N == 0) { return ScriptRuntime.emptyStrings; } String[] array = new String[N]; itsVariables.toArray(array); return array; } public final boolean[] getParamAndVarConst() { int N = itsVariables.size(); boolean[] array = new boolean[N]; for (int i = 0; i < N; i++) if (itsConst.get(i) != null) array[i] = true; return array; } public final void addParam(String name) { // Check addparam is not called after addLocal if (varStart != itsVariables.size()) Kit.codeBug(); // Allow non-unique parameter names: use the last occurrence (parser // will warn about dups) int index = varStart++; itsVariables.add(name); itsConst.add(null); itsVariableNames.put(name, index); } public static final int NO_DUPLICATE = 1; public static final int DUPLICATE_VAR = 0; public static final int DUPLICATE_PARAMETER = -1; public static final int DUPLICATE_CONST = -2; /** * This function adds a variable to the set of var declarations for a * function (or script). This returns an indicator of a duplicate that * overrides a formal parameter (false if this dups a parameter). * @param name variable name * @return 1 if the name is not any form of duplicate, 0 if it duplicates a * non-parameter, -1 if it duplicates a parameter and -2 if it duplicates a * const. */ public final int

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> addVar(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. if (vIndex >= varStart) { Object v = itsConst.get(vIndex); if (v != null) return DUPLICATE_CONST; else return DUPLICATE_VAR; } else return DUPLICATE_PARAMETER; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(null); itsVariableNames.put(name, index); return NO_DUPLICATE; } public final boolean addConst(String name) { int vIndex = itsVariableNames.get(name, -1); if (vIndex != -1) { // There's already a variable or parameter with this name. return false; } int index = itsVariables.size(); itsVariables.add(name); itsConst.add(name); itsVariableNames.put(name, index); return true; } public final void removeParamOrVar(String name) { int i = itsVariableNames.get(name, -1); if (i != -1) { itsVariables.remove(i); itsVariableNames.remove(name); ObjToIntMap.Iterator iter = itsVariableNames.newIterator(); for (iter.start(); !iter.done(); iter.next()) { int v = iter.getValue(); if (v > i) { iter.setValue(v - 1); } } } } public final Object getCompilerData() { return compilerData; } public final void setCompilerData(Object data) { if (data == null) throw new IllegalArgumentException(); // Can only call once if (compilerData != null) throw new IllegalStateException(); compilerData = data; } private int encodedSourceStart; private int encodedSourceEnd; private String sourceName; private int baseLineno = -1; private int endLineno = -1; private ObjArray functions; private ObjArray regexps; // a list of the formal parameters and local variables private ObjArray itsVariables

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.rhino.Node; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Stack; /** * CodePrinter prints out js code in either pretty format or compact format. * * @see CodeGenerator * * */ class CodePrinter { // The number of characters after which we insert a line break in the code static final int DEFAULT_LINE_LENGTH_THRESHOLD = 500; // There are two separate CodeConsumers, one for pretty-printing and // another for compact printing. Both implement the interface // HasGetCode as CodeConsumer does not have a method for getting the // formatted string. // There are two implementations because the CompactCodePrinter // potentially has a very different implementation to the pretty // version. private interface HasGetCode { String getCode(); } private abstract static class MappedCodePrinter extends CodeConsumer { final private Stack<Mapping> mappings; final private List<Mapping> allMappings; final private boolean createSrcMap; MappedCodePrinter(boolean createSrcMap) { this.createSrcMap = createSrcMap; this.mappings = createSrcMap ? new Stack<Mapping>() : null; this.allMappings = createSrcMap ? new ArrayList<Mapping>() : null; } /** * Maintains a mapping from a given node to the position * in the source code at which its generated form was * placed. This position

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> is relative only to the current * run of the CodeConsumer and will be normalized * later on by the SourceMap. * * @see SourceMap */ private static class Mapping { Node node; Position start; Position end; } /** * Starts the source mapping for the given * node at the current position. */ @Override void startSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Mapping mapping = new Mapping(); mapping.node = node; mapping.start = new Position(line, index); mappings.push(mapping); allMappings.add(mapping); } } } /** * Finishes the source mapping for the given * node at the current position. */ @Override void endSourceMapping(Node node) { if (createSrcMap && node.getProp(Node.SOURCEFILE_PROP) != null && node.getLineno() > 0) { int line = getCurrentLineIndex(); int index = getCurrentCharIndex(); // If the index is -1, we are not performing any mapping. if (index >= 0) { Preconditions.checkState( !mappings.empty(), "Mismatch in start and end of mapping"); Mapping mapping = mappings.pop(); mapping.end = new Position(line, index); } } } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ @Override void generateSourceMap(SourceMap map){ if (createSrcMap) { for (Mapping mapping : allMappings) { map.addMapping(mapping.node, mapping.start, mapping.end); } } } /** * Reports to the code consumer that the given line has been cut at the * given position (i.e. a \n has been inserted there). All mappings in * the source maps after that position will be renormalized

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Threshold; } public String getCode() { return code.toString(); } @Override char getLastChar() { return (code.length() > 0) ? code.charAt(code.length() - 1) : '\0'; } @Override int getCurrentBufferLength() { return code.length(); } @Override int getCurrentCharIndex() { return lineLength; } @Override int getCurrentLineIndex() { return lineIndex; } /** * Appends a string to the code, keeping track of the current line length. */ @Override void append(String str) { // For pretty printing: indent at the beginning of the line if (lineLength == 0) { for (int i = 0; i < indent; i++) { code.append(INDENT); lineLength += INDENT.length(); } } code.append(str); lineLength += str.length(); } /** * Adds a newline to the code, resetting the line length and handling * indenting for pretty printing. */ @Override void startNewLine() { if (lineLength > 0) { code.append('\n'); lineIndex++; lineLength = 0; } } @Override void maybeLineBreak() { maybeCutLine(); } /** * This may start a new line if the current line is longer than the line * length threshold. */ @Override void maybeCutLine() { if (lineLength > lineLengthThreshold) { startNewLine(); } } @Override void endLine() { startNewLine(); } @Override void appendBlockStart() { append(" {"); indent++; } @Override void appendBlockEnd() { endLine(); indent--; append("}"); } @Override void listSeparator() { add(", "); maybeLineBreak(); } @Override void endFunction(boolean statementContext) { super.endFunction(statementContext); if (statementContext) { startNewLine(); } } @Override void beginCaseBody() { super.beginCaseBody(); indent++; endLine(); } @Override void endCase

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> this.outputCharset = outCharset; return this; } /** * Whether the input AST guaranteed to be properly formed, fail if it isn't. */ Builder setValidation(boolean validation) { this.validation = validation; return this; } /** * Generates the source code and returns it. */ String build() { if (root == null) { throw new IllegalStateException( "Cannot build without root node being specified"); } Format outputFormat = outputTypes ? Format.TYPED : prettyPrint ? Format.PRETTY : Format.COMPACT; return toSource(root, outputFormat, lineBreak, lineLengthThreshold, sourceMap, outputCharset, validation); } } enum Format { COMPACT, PRETTY, TYPED } /** * Converts a tree to js code */ private static String toSource(Node root, Format outputFormat, boolean lineBreak, int lineLengthThreshold, SourceMap sourceMap, Charset outputCharset, boolean validation) { boolean createSourceMap = (sourceMap != null); CodeConsumer cp = outputFormat == Format.COMPACT ? new CompactCodePrinter( lineBreak, lineLengthThreshold, createSourceMap) : new PrettyCodePrinter(lineLengthThreshold, createSourceMap); CodeGenerator cg = outputFormat == Format.TYPED ? new TypedCodeGenerator(cp, outputCharset) : new CodeGenerator(cp, outputCharset, validation); cg.add(root); String code = ((HasGetCode) cp).getCode(); if (createSourceMap) { cp.generateSourceMap(sourceMap); } return code; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> right, blindScope, condition); } // right type JSType rightType = getTypeIfRefinable(right, blindScope); boolean rightIsRefineable; if (rightType != null) { rightIsRefineable = true; } else { rightIsRefineable = false; rightType = right.getJSType(); blindScope = firstPreciserScopeKnowingConditionOutcome( right, blindScope, condition); } if (condition) { rightType = (rightType == null) ? null : rightType.getRestrictedTypeGivenToBooleanOutcome(condition); // creating new scope if ((leftType != null && leftIsRefineable) || (rightType != null && rightIsRefineable)) { FlowScope informed = blindScope.createChildFlowScope(); if (leftIsRefineable && leftType != null) { declareNameInScope(informed, left, leftType); } if (rightIsRefineable && rightType != null) { declareNameInScope(informed, right, rightType); } return informed; } } return blindScope; } private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right, FlowScope blindScope, boolean condition) { FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, !condition); StaticSlot<JSType> leftVar = leftScope.findUniqueRefinedSlot(blindScope); if (leftVar == null) { return blindScope; } FlowScope rightScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, condition); rightScope = firstPreciserScopeKnowingConditionOutcome( right, rightScope, !condition); StaticSlot<JSType> rightVar = rightScope.findUniqueRefinedSlot(blindScope); if (rightVar == null || !leftVar.getName().equals(rightVar.getName())) { return blindScope; } JSType type = leftVar.getType().getLeastSupertype(rightVar.getType()); FlowScope informed = blindScope.createChildFlowScope(); informed.inferSlotType(leftVar.getName(), type); return informed;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope, boolean outcome) { JSType type = getTypeIfRefinable(name, blindScope); if (type != null) { JSType restrictedType = type.getRestrictedTypeGivenToBooleanOutcome(outcome); FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, name, restrictedType); return informed; } return blindScope; } private FlowScope caseTypeOf(Node node, JSType type, String value, boolean resultEqualsValue, FlowScope blindScope) { JSType restrictedType = getRestrictedByTypeOfResult(type, value, resultEqualsValue); if (restrictedType == null) { return blindScope; } FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, node, restrictedType); return informed; } private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope, boolean outcome) { JSType leftType = getTypeIfRefinable(left, blindScope); if (leftType == null) { return blindScope; } JSType rightType = right.getJSType(); ObjectType targetType = typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE); if (rightType instanceof FunctionType) { targetType = (FunctionType) rightType; } Visitor<JSType> visitor; if (outcome) { visitor = new RestrictByTrueInstanceOfResultVisitor(targetType); } else { visitor = new RestrictByFalseInstanceOfResultVisitor(targetType); } JSType restrictedLeftType = leftType.visit(visitor); if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) { FlowScope informed = blindScope.createChildFlowScope(); declareNameInScope(informed, left, restrictedLeftType); return informed; } return blindScope; } /** * Given 'property in object', ensures that the object has the property in the * informed scope by defining it as a qualified name if the object type lacks * the property and it's not in the blind scope. * @param object The node of the right-

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> code, '$' is often a namespace delimiter. To allow inlining // of namespaced constants, we strip off any namespaces here. int pos = name.lastIndexOf('$'); if (pos >= 0) { name = name.substring(pos + 1); if (name.length() == 0) { return false; } } if (!Character.isUpperCase(name.charAt(0))) { return false; } // hack way of checking that there aren't any lower-case letters return name.toUpperCase().equals(name); } /** * {@inheritDoc} * * <p>This enforces Google's convention about enum key names. They must match * the regular expression {@code [A-Z0-9][A-Z0-9_]*}. * * <p>Examples: * <ul> * <li>A</li> * <li>213</li> * <li>FOO_BAR</li> * </ul> */ @Override public boolean isValidEnumKey(String key) { return ENUM_KEY_PATTERN.matcher(key).matches(); } /** * {@inheritDoc} * * <p>In Google code, parameter names beginning with {@code opt_} are * treated as optional arguments. */ @Override public boolean isOptionalParameter(Node parameter) { return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX); } @Override public boolean isVarArgsParameter(Node parameter) { return VAR_ARGS_NAME.equals(parameter.getString()); } /** * {@inheritDoc} * * <p>In Google code, any global name starting with an underscore is * considered exported. */ @Override public boolean isExported(String name, boolean local) { return !local && name.startsWith("_"); } /** * {@inheritDoc} * * <p>In Google code, private names end with an underscore, and exported * names are never considered private (see {@link #isExported}). */ @Override public boolean isPrivate(String name) { return name.endsWith("_") && !isExported(name); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp.parsing; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.google.javascript.jscomp.mozilla.rhino.CompilerEnvirons; import com.google.javascript.jscomp.mozilla.rhino.Context; import com.google.javascript.jscomp.mozilla.rhino.ErrorReporter; import com.google.javascript.jscomp.mozilla.rhino.EvaluatorException; import com.google.javascript.jscomp.mozilla.rhino.Parser; import com.google.javascript.jscomp.mozilla.rhino.ast.AstRoot; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.jstype.JSTypeRegistry; import java.io.IOException; import java.util.ResourceBundle; import java.util.Set; import java.util.logging.Logger; public class ParserRunner { private static final String configResource = "com.google.javascript.jscomp.parsing.ParserConfig"; private static Set<String> annotationNames = null; // Should never need to instantiate class of static methods. private ParserRunner() {} public static Config createConfig( JSTypeRegistry typeRegistry, boolean isIdeMode) { return new Config( typeRegistry, getAnnotationNames(), isIdeMode); } /** * Gets a list of extra annotations that are OK, even if the parser * doesn't have handlers for them built-in. */ static Set<String> getAnnotationNames() { init

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>AnnotationNames(); return annotationNames; } private static synchronized void initAnnotationNames() { if (annotationNames != null) { return; } Set<String> trimmedNames = Sets.newHashSet(); ResourceBundle config = ResourceBundle.getBundle(configResource); String[] names = config.getString("jsdoc.annotations").split(","); for (String name : names) { trimmedNames.add(name.trim()); } annotationNames = ImmutableSet.copyOf(trimmedNames); } /** * Parses the JavaScript text given by a reader. * * @param sourceName The filename. * @param sourceString Source code from the file. * @param errorReporter An error. * @param logger A logger. * @return The AST of the given text. * @throws IOException */ public static Node parse(String sourceName, String sourceString, Config config, ErrorReporter errorReporter, Logger logger) throws IOException { Context cx = Context.enter(); cx.setErrorReporter(errorReporter); cx.setLanguageVersion(Context.VERSION_1_5); CompilerEnvirons compilerEnv = new CompilerEnvirons(); compilerEnv.initFromContext(cx); compilerEnv.setRecordingComments(true); compilerEnv.setRecordingLocalJsDocComments(true); compilerEnv.setWarnTrailingComma(true); if (config.isIdeMode) { compilerEnv.setReservedKeywordAsIdentifier(true); compilerEnv.setAllowMemberExprAsFunctionName(true); } Parser p = new Parser(compilerEnv, errorReporter); AstRoot astRoot = null; try { astRoot = p.parse(sourceString, sourceName, 1); } catch (EvaluatorException e) { logger.info("Error parsing " + sourceName + ": " + e.getMessage()); } finally { Context.exit(); } Node root = null; if (astRoot != null) { root = IRFactory.transformTree( astRoot, sourceString, config, errorReporter); root.setIsSyntheticBlock(true); } return root; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * Covert EXPR_VOID to EXPR_RESULT to simplify the rest of the code. */ private void normalizeNodeTypes(Node n) { if (n.getType() == Token.EXPR_VOID) { n.setType(Token.EXPR_RESULT); reportChange(); } // Remove unused properties to minimize differences between ASTs // produced by the two parsers. if (n.getType() == Token.FUNCTION) { Preconditions.checkState(n.getProp(Node.FUNCTION_PROP) == null); } normalizeBlocks(n); for (Node child = n.getFirstChild(); child != null; child = child.getNext()) { // This pass is run during the CompilerTestCase validation, so this // parent pointer check serves as a more general check. Preconditions.checkState(child.getParent() == n); normalizeNodeTypes(child); } } /** * Add blocks to IF, WHILE, DO, etc. */ private void normalizeBlocks(Node n) { if (NodeUtil.isControlStructure(n) && n.getType() != Token.LABEL && n.getType() != Token.SWITCH) { for (Node c = n.getFirstChild(); c != null; c = c.getNext()) { if (NodeUtil.isControlStructureCodeBlock(n,c) && c.getType() != Token.BLOCK) { Node newBlock = new Node(Token.BLOCK); n.replaceChild(c, newBlock); if (c.getType() != Token.EMPTY) { newBlock.addChildrenToFront(c); } else { newBlock.setWasEmptyNode(true); } c = newBlock; reportChange(); } } } } /** * Normalize where annotations appear on the AST. Copies * around existing JSDoc annotations as well as internal annotations. */ static class PrepareAnnotations extends NodeTraversal.AbstractPostOrderCallback { private final AbstractCompiler compiler; private final CodingConvention convention; PrepareAnnotations(AbstractCompiler compiler) { this.compiler = compiler; this.convention = compiler.getCodingConvention(); } /** * * In the AST that Rhino gives us, it needs to make a distinction * between jsdoc

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> on the object literal node and jsdoc on the object literal * value. For example, * <pre> * var x = { * / JSDOC / * a: 'b', * c: / JSDOC / 'd' * }; * </pre> * * But in few narrow cases (in particular, function literals), it's * a lot easier for us if the doc is attached to the value. */ public void visit(NodeTraversal t, Node n, Node parent) { int nType = n.getType(); switch (nType) { case Token.NAME: case Token.STRING: String nString = n.getString(); if (nType == Token.NAME && n.getParent().getType() == Token.CALL && "eval".equals(nString)) { n.putBooleanProp(Node.DIRECT_EVAL, true); } if (convention.isConstant(nString)) { n.putBooleanProp(Node.IS_CONSTANT_NAME, true); } break; case Token.FUNCTION: JSDocInfo fnInfo = n.getJSDocInfo(); if (fnInfo == null) { // Look for the info on other nodes. if (parent.getType() == Token.ASSIGN) { // on ASSIGNs fnInfo = parent.getJSDocInfo(); } else if (parent.getType() == Token.NAME) { // on var NAME = function() { ... }; fnInfo = parent.getParent().getJSDocInfo(); } } // Compute which function parameters are optional and // which are var_args. Node args = n.getFirstChild().getNext(); for (Node arg = args.getFirstChild(); arg != null; arg = arg.getNext()) { String argName = arg.getString(); JSTypeExpression typeExpr = fnInfo == null ? null : fnInfo.getParameterType(argName); if (convention.isOptionalParameter(arg) || typeExpr != null && typeExpr.isOptionalArg()) { arg.putBooleanProp(Node.IS_OPTIONAL_PARAM, true); } if (convention.isVarArgsParameter(arg) || typeExpr != null && typeExpr.isVarArgs())

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Lists; import com.google.javascript.jscomp.MakeDeclaredNamesUnique.InlineRenamer; import com.google.javascript.rhino.Node; /** * @author johnlenz@google.com (John Lenz) */ public class MakeDeclaredNamesUniqueTest extends CompilerTestCase { private boolean useDefaultRenamer = false; private boolean invert = false; private boolean removeConst = false; private final String localNamePrefix = "unique_"; @Override public CompilerPass getProcessor(final Compiler compiler) { if (!invert) { return new CompilerPass() { @Override public void process(Node externs, Node root) { compiler.resetUniqueNameId(); MakeDeclaredNamesUnique renamer = null; if (useDefaultRenamer) { renamer = new MakeDeclaredNamesUnique(); } else { renamer = new MakeDeclaredNamesUnique( new InlineRenamer( compiler.getUniqueNameIdSupplier(), localNamePrefix, removeConst)); } NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), renamer); } }; } else { return MakeDeclaredNamesUnique.getContextualRenameInverter(compiler); } } @Override protected int getNumRepetitions() { // The normalize pass is only run once. return 1; } @Override public void setUp() { removeConst = false; invert = false; useDefaultRenamer = false; } public void test

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>jstype.JSType; import com.google.javascript.rhino.jstype.JSTypeNative; import com.google.javascript.rhino.jstype.JSTypeRegistry; import com.google.javascript.rhino.jstype.ObjectType; import java.text.MessageFormat; import java.util.Iterator; import java.util.List; /** * A central reporter for all type violations: places where the programmer * has annotated a variable (or property) with one type, but has assigned * another type to it. * * Also doubles as a central repository for all type violations, so that * type-based optimizations (like AmbiguateProperties) can be fault-tolerant. * * @author nicksantos@google.com (Nick Santos) */ class TypeValidator { private final AbstractCompiler compiler; private final JSTypeRegistry typeRegistry; private final JSType allValueTypes; // TODO(nicksantos): Provide accessors to better filter the list of type // mismatches. For example, if we pass (Cake|null) where only Cake is // allowed, that doesn't mean we should invalidate all Cakes. private final List<TypeMismatch> mismatches = Lists.newArrayList(); // User warnings private static final String FOUND_REQUIRED = "{0}\n" + "found : {1}\n" + "required: {2}"; static final DiagnosticType INVALID_CAST = DiagnosticType.warning("JSC_INVALID_CAST", "invalid cast - must be a subtype or supertype\n" + "from: {0}\n" + "to : {1}"); static final DiagnosticType TYPE_MISMATCH_WARNING = DiagnosticType.warning( "JSC_TYPE_MISMATCH", "{0}"); static final DiagnosticType MISSING_EXTENDS_TAG_WARNING = DiagnosticType.warning( "JSC_MISSING_EXTENDS_TAG", "Missing @extends tag on type {0}"); static final DiagnosticType DUP_VAR_DECLARATION = DiagnosticType.warning("JSC_DUP_VAR_DECLARATION", "variable {0} redefined with type {1}, " + "original definition at {2}:{3

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * @param t The node traversal. * @param n The node to issue warnings on. * @param overridingType The overriding type. * @param hiddenType The type of the property being overridden. * @param propertyName The name of the property, for use in the * warning message. * @param ownerType The type of the owner of the property, for use * in the warning message. */ void expectCanOverride(NodeTraversal t, Node n, JSType overridingType, JSType hiddenType, String propertyName, JSType ownerType) { if (!overridingType.canAssignTo(hiddenType)) { registerMismatch(overridingType, hiddenType); compiler.report( JSError.make(t, n, HIDDEN_PROPERTY_MISMATCH, propertyName, ownerType.toString(), hiddenType.toString(), overridingType.toString())); } } /** * Expect that the first type is the direct superclass of the second type. * * @param t The node traversal. * @param n The node where warnings should point to. * @param superObject The expected super instance type. * @param subObject The sub instance type. */ void expectSuperType(NodeTraversal t, Node n, ObjectType superObject, ObjectType subObject) { FunctionType subCtor = subObject.getConstructor(); ObjectType declaredSuper = subObject.getImplicitPrototype().getImplicitPrototype(); if (!declaredSuper.equals(superObject)) { if (declaredSuper.equals(getNativeType(OBJECT_TYPE))) { compiler.report( JSError.make(t, n, MISSING_EXTENDS_TAG_WARNING, subObject.toString())); registerMismatch(superObject, declaredSuper); } else { mismatch(t.getSourceName(), n, "mismatch in declaration of superclass type", superObject, declaredSuper); } // Correct the super type. if (!subCtor.hasCachedValues()) { subCtor.setPrototypeBasedOn(superObject); } } } /** * Expect that the first type can be cast to the second type. The first type * should be either a subtype or supertype of the second. * * @param t The node traversal. * @param n The node where

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> warnings should point. * @param type The type being cast from. * @param castType The type being cast to. */ void expectCanCast(NodeTraversal t, Node n, JSType type, JSType castType) { castType = castType.restrictByNotNullOrUndefined(); type = type.restrictByNotNullOrUndefined(); if (!type.canAssignTo(castType) && !castType.canAssignTo(type)) { compiler.report( JSError.make(t, n, INVALID_CAST, castType.toString(), type.toString())); registerMismatch(type, castType); } } /** * Expect that the given variable has not been declared with a type. * * @param sourceName The name of the source file we're in. * @param n The node where warnings should point to. * @param parent The parent of {@code n}. * @param var The variable that we're checking. * @param variableName The name of the variable. * @param newType The type being applied to the variable. Mostly just here * for the benefit of the warning. */ void expectUndeclaredVariable(String sourceName, Node n, Node parent, Var var, String variableName, JSType newType) { boolean allowDupe = false; if (n.getType() == Token.GETPROP) { JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); } JSType varType = var.getType(); // Only report duplicate declarations that have types. Other duplicates // will be reported by the syntactic scope creator later in the // compilation process. if (varType != null && varType != typeRegistry.getNativeType(UNKNOWN_TYPE) && newType != null && newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) { // If there are two typed declarations of the same variable, that // is an error and the second declaration is ignored, except in the // case of native types. A null input type means that the declaration // was made in TypedScopeCreator#createInitial

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Scope and is a // native type. if (var.input == null) { n.setJSType(varType); if (parent.getType() == Token.VAR) { if (n.getFirstChild() != null) { n.getFirstChild().setJSType(varType); } } else { Preconditions.checkState(parent.getType() == Token.FUNCTION); parent.setJSType(varType); } } else { // Always warn about duplicates if the overridden type does not // match the original type. // // If the types match, suppress the warning iff there was a @suppress // tag, or if the original declaration was a stub. if (!(allowDupe || var.getParentNode().getType() == Token.EXPR_RESULT) || !newType.equals(varType)) { compiler.report( JSError.make(sourceName, n, DUP_VAR_DECLARATION, variableName, newType.toString(), var.getInputName(), String.valueOf(var.nameNode.getLineno()), varType.toString())); } } } } /** * Expect that all properties on interfaces that this type implements are * implemented. */ void expectAllInterfacePropertiesImplemented(FunctionType type) { ObjectType instance = type.getInstanceType(); for (ObjectType implemented : type.getAllImplementedInterfaces()) { if (implemented.getImplicitPrototype() != null) { for (String prop : implemented.getImplicitPrototype().getOwnPropertyNames()) { if (!instance.hasProperty(prop)) { Node source = type.getSource(); Preconditions.checkNotNull(source); String sourceName = (String) source.getProp(Node.SOURCENAME_PROP); sourceName = sourceName == null ? "" : sourceName; compiler.report(JSError.make(sourceName, source, INTERFACE_METHOD_NOT_IMPLEMENTED, prop, implemented.toString(), instance.toString())); registerMismatch(instance, implemented); } } } } } /** * Report a type mismatch */ private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSType required) { mismatch(t.getSourceName(), n, msg, found, required); }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> private void mismatch(NodeTraversal t, Node n, String msg, JSType found, JSTypeNative required) { mismatch(t, n, msg, found, getNativeType(required)); } private void mismatch(String sourceName, Node n, String msg, JSType found, JSType required) { registerMismatch(found, required); compiler.report( JSError.make(sourceName, n, TYPE_MISMATCH_WARNING, formatFoundRequired(msg, found, required))); } private void registerMismatch(JSType found, JSType required) { // Don't register a mismatch for differences in null or undefined or if the // code didn't downcast. found = found.restrictByNotNullOrUndefined(); required = required.restrictByNotNullOrUndefined(); if (found.canAssignTo(required) || required.canAssignTo(found)) { return; } mismatches.add(new TypeMismatch(found, required)); if (found instanceof FunctionType && required instanceof FunctionType) { FunctionType fnTypeA = ((FunctionType) found); FunctionType fnTypeB = ((FunctionType) required); Iterator<Node> paramItA = fnTypeA.getParameters().iterator(); Iterator<Node> paramItB = fnTypeB.getParameters().iterator(); while (paramItA.hasNext() && paramItB.hasNext()) { registerIfMismatch(paramItA.next().getJSType(), paramItB.next().getJSType()); } registerIfMismatch(fnTypeA.getReturnType(), fnTypeB.getReturnType()); } } private void registerIfMismatch(JSType found, JSType required) { if (found != null && required != null && !found.canAssignTo(required)) { registerMismatch(found, required); } } /** * Formats a found/required error message. */ private String formatFoundRequired(String description, JSType found, JSType required) { return MessageFormat.format(FOUND_REQUIRED, description, found, required); } /** * Given a node, get a human-readable name for the type of that node so * that will be easy for the programmer to find the original declaration. * * For example, if SubFoo's property "

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> should log this and analyze to track // down why it happens. This is not critical and will be resolved over // time as the type checker is extended. return getNativeType(UNKNOWN_TYPE); } else { return jsType; } } private JSType getNativeType(JSTypeNative typeId) { return typeRegistry.getNativeType(typeId); } /** * Signals that the first type and the second type have been * used interchangeably. * * Type-based optimizations should take this into account * so that they don't wreck code with type warnings. */ static class TypeMismatch { final JSType typeA; final JSType typeB; /** * It's the responsibility of the class that creates the * {@code TypeMismatch} to ensure that {@code a} and {@code b} are * non-matching types. */ TypeMismatch(JSType a, JSType b) { this.typeA = a; this.typeB = b; } @Override public boolean equals(Object object) { if (object instanceof TypeMismatch) { TypeMismatch that = (TypeMismatch) object; return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB)) || (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB)); } return false; } @Override public int hashCode() { return Objects.hashCode(typeA, typeB); } @Override public String toString() { return "(" + typeA + ", " + typeB + ")"; } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp.parsing; import com.google.common.collect.ImmutableMap; import com.google.javascript.rhino.jstype.JSTypeRegistry; import java.util.Map; import java.util.Set; /** * Configuration for the AST factory. Should be shared across AST creation * for all files of a compilation process. * * @author nicksantos@google.com (Nick Santos) */ public class Config { /** * Central registry for type info. */ final JSTypeRegistry registry; /** * Whether to parse the descriptions of jsdoc comments. */ final boolean parseJsDocDocumentation; /** * Whether we're in ide mode. */ final boolean isIdeMode; /** * Recognized JSDoc annotations, mapped from their name to their internal * representation. */ final Map<String, Annotation> annotationNames; /** * Annotation names. */ Config(JSTypeRegistry registry, Set<String> annotationWhitelist, boolean isIdeMode) { this.registry = registry; this.annotationNames = buildAnnotationNames(annotationWhitelist); this.parseJsDocDocumentation = isIdeMode; this.isIdeMode = isIdeMode; } /** * Create the annotation names from the user-specified * annotation whitelist. */ private static Map<String, Annotation> buildAnnotationNames( Set<String> annotationWhitelist) { ImmutableMap.Builder<String, Annotation> annotationBuilder = ImmutableMap.builder(); annotationBuilder.putAll(Annotation.recognizedAnnotations); for (String unrecognized

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>JSC_BAD_JSDOC_ANNOTATION", "Parse error. {0}"); // A map of Rhino messages to their DiagnosticType. private final Map<String, DiagnosticType> typeMap; private final AbstractCompiler compiler; /** * For each message such as "Not a good use of {0}", replace the place * holder {0} with a wild card that matches all possible strings. * Also put the any non-place-holder in quotes for regex matching later. */ private String replacePlaceHolders(String s) { s = Pattern.quote(s); return s.replaceAll("\\{\\d+\\}", "\\\\E.*\\\\Q"); } private RhinoErrorReporter(AbstractCompiler compiler) { this.compiler = compiler; typeMap = ImmutableMap.of( // Extra @fileoverview replacePlaceHolders( ScriptRuntime.getMessage0("msg.jsdoc.fileoverview.extra")), EXTRA_FILEOVERVIEW, // Trailing comma replacePlaceHolders( com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime .getMessage0("msg.extra.trailing.comma")), TRAILING_COMMA, // Duplicate parameter replacePlaceHolders( com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime .getMessage0("msg.dup.parms")), DUPLICATE_PARAM, // Unknown @annotations. replacePlaceHolders(ScriptRuntime.getMessage0("msg.bad.jsdoc.tag")), BAD_JSDOC_ANNOTATION); } public static com.google.javascript.jscomp.mozilla.rhino.ErrorReporter forNewRhino(AbstractCompiler compiler) { return new NewRhinoErrorReporter(compiler); } public static ErrorReporter forOldRhino(AbstractCompiler compiler) { return new OldRhinoErrorReporter(compiler); } public void warning(String message, String sourceName, int line, String lineSource, int lineOffset) { compiler.report( makeError(message, sourceName, line, lineOffset, CheckLevel.WARNING)); } public void error(String message, String sourceName, int line, String lineSource, int lineOffset) { compiler.report( makeError(message, source

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) || that.isObject()) { return UNKNOWN; } return FALSE; } @Override public boolean isBooleanValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE); } @Override public String toString() { return "boolean"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseBooleanType(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.javascript.jscomp.GlobalNamespace.Name; import com.google.javascript.jscomp.GlobalNamespace.Ref; import com.google.javascript.jscomp.NodeTraversal.Callback; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.text.MessageFormat; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Set; /** * Process variables annotated as {@code @define}. A define is * a special constant that may be overridden by later files and * manipulated by the compiler, much like C preprocessor {@code #define}s. * * @author nicksantos@google.com (Nick Santos) */ class ProcessDefines implements CompilerPass { /** * Defines in this set will not be flagged with "unknown define" warnings. * There are legacy flags that always set these defines, even when they * might not be in the binary. */ private static final Set<String> KNOWN_DEFINES = Sets.newHashSet("COMPILED"); private final AbstractCompiler compiler; private final Map<String, Node> dominant

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> = def.getValue(); Node inputValue = dominantReplacements.get(defineName); Node finalValue = inputValue != null ? inputValue : info.getLastValue(); if (finalValue != info.initialValue) { info.initialValueParent.replaceChild( info.initialValue, finalValue.cloneTree()); compiler.addToDebugLog("Overriding @define variable " + defineName); changed = changed || finalValue.getType() != info.initialValue.getType() || !finalValue.isEquivalentTo(info.initialValue); } } if (changed) { compiler.reportCodeChange(); } Set<String> unusedReplacements = dominantReplacements.keySet(); unusedReplacements.removeAll(allDefines.keySet()); unusedReplacements.removeAll(KNOWN_DEFINES); for (String unknownDefine : unusedReplacements) { compiler.report(JSError.make(UNKNOWN_DEFINE_WARNING, unknownDefine)); } } private static String format(MessageFormat format, Object... params) { return format.format(params); } /** * Finds all defines, and creates a {@link DefineInfo} data structure for * each one. * @return A map of {@link DefineInfo} structures, keyed by name. */ private Map<String, DefineInfo> collectDefines(Node root, GlobalNamespace namespace) { // Find all the global names with a @define annotation List<Name> allDefines = Lists.newArrayList(); for (Name name : namespace.getNameIndex().values()) { if (name.docInfo != null && name.docInfo.isDefine()) { allDefines.add(name); } else if (name.refs != null) { for (Ref ref : name.refs) { Node n = ref.node; Node parent = ref.node.getParent(); JSDocInfo info = n.getJSDocInfo(); if (info == null && parent.getType() == Token.VAR && parent.hasOneChild()) { info = parent.getJSDocInfo(); } if (info != null && info.isDefine()) { allDefines.add(name); break; } } } } CollectDefines pass = new CollectDefines(compiler, all

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Defines); NodeTraversal.traverse(compiler, root, pass); return pass.getAllDefines(); } /** * Finds all assignments to @defines, and figures out the last value of * the @define. */ private static final class CollectDefines implements Callback { private final AbstractCompiler compiler; private final Map<String, DefineInfo> assignableDefines; private final Map<String, DefineInfo> allDefines; private final Map<Node, RefInfo> allRefInfo; // A hack that allows us to remove ASSIGN/VAR statements when // we're currently visiting one of the children of the assign. private Node lvalueToRemoveLater = null; // A stack tied to the node traversal, to keep track of whether // we're in a conditional block. If 1 is at the top, assignment to // a define is allowed. Otherwise, it's not allowed. private final Deque<Integer> assignAllowed; CollectDefines(AbstractCompiler compiler, List<Name> listOfDefines) { this.compiler = compiler; this.allDefines = Maps.newHashMap(); assignableDefines = Maps.newHashMap(); assignAllowed = new ArrayDeque<Integer>(); assignAllowed.push(1); // Create a map of references to defines keyed by node for easy lookup allRefInfo = Maps.newHashMap(); for (Name name : listOfDefines) { if (name.declaration != null) { allRefInfo.put(name.declaration.node, new RefInfo(name.declaration, name)); } if (name.refs != null) { for (Ref ref : name.refs) { // If there's a TWIN def, only put one of the twins in. if (ref.getTwin() == null || !ref.getTwin().isSet()) { allRefInfo.put(ref.node, new RefInfo(ref, name)); } } } } } /** * Get a map of {@link DefineInfo} structures, keyed by the name of * the define. */ Map<String, DefineInfo> getAllDefines() { return allDefines; } /** * Keeps track of whether the traversal is in a conditional branch. * We traverse all nodes of the parse tree. */ public boolean shouldTra

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>verse(NodeTraversal nodeTraversal, Node n, Node parent) { updateAssignAllowedStack(n, true); return true; } public void visit(NodeTraversal t, Node n, Node parent) { RefInfo refInfo = allRefInfo.get(n); if (refInfo != null) { Ref ref = refInfo.ref; Name name = refInfo.name; String fullName = name.fullName(); switch (ref.type) { case SET_FROM_GLOBAL: case SET_FROM_LOCAL: Node valParent = getValueParent(ref); Node val = valParent.getLastChild(); if (valParent.getType() == Token.ASSIGN && name.isSimpleName() && name.declaration == ref) { // For defines, it's an error if a simple name is assigned // before it's declared compiler.report( JSError.make(t, val, INVALID_DEFINE_INIT_ERROR, fullName)); } else if (processDefineAssignment(t, fullName, val, valParent)) { // remove the assignment so that the variable is still declared, // but no longer assigned to a value, e.g., // DEF_FOO = 5; // becomes "5;" // We can't remove the ASSIGN/VAR when we're still visiting its // children, so we'll have to come back later to remove it. refInfo.name.removeRef(ref); lvalueToRemoveLater = valParent; } break; default: if (t.inGlobalScope()) { // Treat this as a reference to a define in the global scope. // After this point, the define must not be reassigned, // or it's an error. DefineInfo info = assignableDefines.get(fullName); if (info != null) { setDefineInfoNotAssignable(info, t); assignableDefines.remove(fullName); } } break; } } if (!t.inGlobalScope() && n.getJSDocInfo() != null && n.getJSDocInfo().isDefine()) { // warn about @define annotations in local scopes compiler.report( JSError.make(t, n, NON_GLOBAL_DEFINE_INIT_ERROR, "")); } if

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (lvalueToRemoveLater == n) { lvalueToRemoveLater = null; if (n.getType() == Token.ASSIGN) { Node last = n.getLastChild(); n.removeChild(last); parent.replaceChild(n, last); } else { Preconditions.checkState(n.getType() == Token.NAME); n.removeChild(n.getFirstChild()); } compiler.reportCodeChange(); } if (n.getType() == Token.CALL) { if (t.inGlobalScope()) { // If there's a function call in the global scope, // we just say it's unsafe and freeze all the defines. // // NOTE(nicksantos): We could be a lot smarter here. For example, // ReplaceOverriddenVars keeps a call graph of all functions and // which functions/variables that they reference, and tries // to statically determine which functions are "safe" and which // are not. But this would be overkill, expecially because // the intended use of defines is with config_files, where // all the defines are at the top of the bundle. for (DefineInfo info : assignableDefines.values()) { setDefineInfoNotAssignable(info, t); } assignableDefines.clear(); } } updateAssignAllowedStack(n, false); } /** * Determines whether assignment to a define should be allowed * in the subtree of the given node, and if not, records that fact. * * @param n The node whose subtree we're about to enter or exit. * @param entering True if we're entering the subtree, false otherwise. */ private void updateAssignAllowedStack(Node n, boolean entering) { switch (n.getType()) { case Token.CASE: case Token.FOR: case Token.FUNCTION: case Token.HOOK: case Token.IF: case Token.SWITCH: case Token.WHILE: if (entering) { assignAllowed.push(0); } else { assignAllowed.remove(); } break; } } /** * Determines whether assignment to a define should be allowed * at the current point of the traversal. */ private boolean isAssignAllowed() { return assignAllowed.element()

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> == 1; } /** * Tracks the given define. * * @param t The current traversal, for context. * @param name The full name for this define. * @param value The value assigned to the define. * @param valueParent The parent node of value. * @return Whether we should remove this assignment from the parse tree. */ private boolean processDefineAssignment(NodeTraversal t, String name, Node value, Node valueParent) { if (value == null || !NodeUtil.isValidDefineValue(value, allDefines.keySet())) { compiler.report( JSError.make(t, value, INVALID_DEFINE_INIT_ERROR, name)); } else if (!isAssignAllowed()) { compiler.report( JSError.make(t, valueParent, NON_GLOBAL_DEFINE_INIT_ERROR, name)); } else { DefineInfo info = allDefines.get(name); if (info == null) { // First declaration of this define. info = new DefineInfo(value, valueParent); allDefines.put(name, info); assignableDefines.put(name, info); } else if (info.recordAssignment(value)) { // The define was already initialized, but this is a safe // re-assignment. return true; } else { // The define was already initialized, and this is an unsafe // re-assignment. compiler.report( JSError.make(t, valueParent, DEFINE_NOT_ASSIGNABLE_ERROR, name, info.getReasonWhyNotAssignable())); } } return false; } /** * Gets the parent node of the value for any assignment to a Name. * For example, in the assignment * {@code var x = 3;} * the parent would be the NAME node. */ private static Node getValueParent(Ref ref) { // there are two types of declarations: VARs and ASSIGNs return ref.node.getParent() != null && ref.node.getParent().getType() == Token.VAR ? ref.node : ref.node.getParent(); } /** * Records the fact that because of the current node in the node traversal, * the define can't ever be assigned again. * * @param

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>} until requested by * {@link #getControlFlowGraph()}. Note that {@link ArrayDeque} does not allow * {@code null} elements, so {@link LinkedList} is used instead. */ Deque<ControlFlowGraph<Node>> cfgs = new LinkedList<ControlFlowGraph<Node>>(); /** The current source file name */ private String sourceName; /** The scope creator */ private ScopeCreator scopeCreator; /** Possible callback for scope entry and exist **/ private ScopedCallback scopeCallback; /** * Callback */ public interface Callback { /** * <p>Visits a node in pre order (before visiting its children) and decides * whether this node's children should be traversed. If children are * traversed, they will be visited by * {@link #visit(NodeTraversal, Node, Node)} in post order.</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> * @return whether the children of this node should be visited */ boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent); /** * <p>Visits a node in post order (after its children have been visited). * A node is visited only if all its parents should be traversed * ({@link #shouldTraverse(NodeTraversal, Node, Node)}).</p> * <p>Implementations can have side effects (e.g. modifying the parse * tree).</p> */ void visit(NodeTraversal t, Node n, Node parent); } /** * Callback that also knows about scope changes */ public interface ScopedCallback extends Callback { /** * Called immediately after entering a new scope. The new scope can * be accessed through t.getScope() */ void enterScope(NodeTraversal t); /** * Called immediately before exiting a scope. The ending scope can * be accessed through t.getScope() */ void exitScope(NodeTraversal t); } /** * Abstract callback to visit all nodes in post order. * */ public abstract static class AbstractPostOrderCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return true; } } /** * Abstract callback to

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> visit all nodes but not traverse into function * bodies. */ public abstract static class AbstractShallowCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { // We do want to traverse the name of a named function, but we don't // want to traverse the arguments or body. return parent == null || parent.getType() != Token.FUNCTION || n == parent.getFirstChild(); } } /** * Abstract callback to visit all structure and statement nodes but doesn't * traverse into functions or expressions. */ public abstract static class AbstractShallowStatementCallback implements Callback { public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return parent == null || NodeUtil.isControlStructure(parent) || NodeUtil.isStatementBlock(parent); } } /** * Abstract callback to visit a pruned set of nodes. * */ public abstract static class AbstractNodeTypePruningCallback implements Callback { private final Set<Integer> nodeTypes; private final boolean include; /** * Creates an abstract pruned callback. * @param nodeTypes the nodes to include in the traversal */ public AbstractNodeTypePruningCallback(Set<Integer> nodeTypes) { this(nodeTypes, true); } /** * Creates an abstract pruned callback. * @param nodeTypes the nodes to include/exclude in the traversal * @param include whether to include or exclude the nodes in the traversal */ public AbstractNodeTypePruningCallback(Set<Integer> nodeTypes, boolean include) { this.nodeTypes = nodeTypes; this.include = include; } public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent) { return include == nodeTypes.contains(n.getType()); } } /** * Creates a node traversal using the specified callback interface. */ public NodeTraversal(AbstractCompiler compiler, Callback cb) { this(compiler, cb, new SyntacticScopeCreator(compiler)); } /** * Creates a node traversal using the specified callback interface * and the scope creator. */ public NodeTraversal(AbstractCompiler compiler, Callback cb, ScopeCreator scopeCreator) { this.callback = cb;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> if (cb instanceof ScopedCallback) { this.scopeCallback = (ScopedCallback) cb; } this.compiler = compiler; this.sourceName = ""; this.scopeCreator = scopeCreator; } private void throwUnexpectedException(Exception unexpectedException) { // If there's an unexpected exception, try to get the // line number of the code that caused it. String message = unexpectedException.getMessage(); // TODO(user): It is possible to get more information if curNode or // its parent is missing. We still have the scope stack in which it is still // very useful to find out at least which function caused the exception. if (!sourceName.isEmpty()) { message = unexpectedException.getMessage() + "\n" + formatNodeContext("Node", curNode) + (curNode == null ? "" : formatNodeContext("Parent", curNode.getParent())); } compiler.throwInternalError(message, unexpectedException); } private String formatNodeContext(String label, Node n) { if (n == null) { return " " + label + ": NULL"; } return " " + label + "(" + n.toString(false, false, false) + "): " + formatNodePosition(n); } /** * Traverses a parse tree recursively. */ public void traverse(Node root) { try { sourceName = ""; curNode = root; pushScope(root); traverseBranch(root, null); popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException); } } public void traverseRoots(Node ... roots) { traverseRoots(Lists.newArrayList(roots)); } public void traverseRoots(List<Node> roots) { if (roots.isEmpty()) { return; } try { Node scopeRoot = roots.get(0).getParent(); Preconditions.checkState(scopeRoot != null); sourceName = ""; curNode = scopeRoot; pushScope(scopeRoot); for (Node root : roots) { Preconditions.checkState(root.getParent() == scopeRoot); traverseBranch(root, scopeRoot); } popScope(); } catch (Exception unexpectedException) { throwUnexpectedException(unexpectedException

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>code null} */ protected void traverseInnerNode(Node node, Node parent, Scope refinedScope) { Preconditions.checkNotNull(parent); if (refinedScope != null && getScope() != refinedScope) { curNode = node; pushScope(refinedScope); traverseBranch(node, parent); popScope(); } else { traverseBranch(node, parent); } } /** * Gets the compiler. */ public Compiler getCompiler() { // TODO(nicksantos): Remove this type cast. This is just temporary // while refactoring. return (Compiler) compiler; } /** * Gets the current line number, or zero if it cannot be determined. The line * number is retrieved lazily as a running time optimization. */ public int getLineNumber() { Node cur = curNode; while (cur != null) { int line = cur.getLineno(); if (line >=0) { return line; } cur = cur.getParent(); } return 0; } /** * Gets the current input source name. * * @return A string that may be empty, but not null */ public String getSourceName() { return sourceName; } /** * Gets the current input source. */ public CompilerInput getInput() { return compiler.getInput(sourceName); } /** * Gets the current input module. */ public JSModule getModule() { CompilerInput input = getInput(); return input == null ? null : input.getModule(); } /** Returns the node currently being traversed. */ public Node getCurrentNode() { return curNode; } /** * Traverses a node recursively. */ public static void traverse( AbstractCompiler compiler, Node root, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverse(root); } /** * Traverses a list of node trees. */ public static void traverseRoots( AbstractCompiler compiler, List<Node> roots, Callback cb) { NodeTraversal t = new NodeTraversal(compiler, cb); t.traverseRoots(roots); } /** * Traverses a branch. */ @SuppressWarnings("

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>fallthrough") private void traverseBranch(Node n, Node parent) { int type = n.getType(); if (type == Token.SCRIPT) { sourceName = getSourceName(n); } curNode = n; if (!callback.shouldTraverse(this, n, parent)) return; switch (type) { case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block traverseBranch(n.getFirstChild(), n); traverseBranch(n.getFirstChild().getNext().getNext(), n); break; case Token.FUNCTION: traverseFunction(n, parent); break; default: for (Node child = n.getFirstChild(); child != null; ) { // child could be replaced, in which case our child node // would no longer point to the true next Node next = child.getNext(); traverseBranch(child, n); child = next; } break; } curNode = n; callback.visit(this, n, parent); } /** * Traverses a function. */ private void traverseFunction(Node n, Node parent) { Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getType() == Token.FUNCTION); final Node fnName = n.getFirstChild(); boolean anonymous = parent != null && NodeUtil.isFunctionAnonymous(n); if (!anonymous) { // Named functions are parent of the containing scope. traverseBranch(fnName, n); } curNode = n; pushScope(n); if (anonymous) { // Anonymous function names are parent of the contained scope. traverseBranch(fnName, n); } final Node args = fnName.getNext(); final Node body = args.getNext(); // Args traverseBranch(args, n); // Body Preconditions.checkState(body.getNext() == null && body.getType() == Token.BLOCK); traverseBranch(body, n); popScope(); } /** Examines the functions stack for the last instance of a function node. */

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> @SuppressWarnings("unchecked") public Node getEnclosingFunction() { if (scopes.size() + scopeRoots.size() < 2) { return null; } else { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } } /** Creates a new scope (e.g. when entering a function). */ private void pushScope(Node node) { Preconditions.checkState(curNode != null); scopeRoots.push(node); cfgs.push(null); if (scopeCallback != null) { scopeCallback.enterScope(this); } } /** Creates a new scope (e.g. when entering a function). */ private void pushScope(Scope s) { Preconditions.checkState(curNode != null); scopes.push(s); cfgs.push(null); if (scopeCallback != null) { scopeCallback.enterScope(this); } } /** Pops back to the previous scope (e.g. when leaving a function). */ private void popScope() { if (scopeCallback != null) { scopeCallback.exitScope(this); } if (scopeRoots.isEmpty()) { scopes.pop(); } else { scopeRoots.pop(); } cfgs.pop(); } /** Gets the current scope. */ public Scope getScope() { Scope scope = scopes.isEmpty() ? null : scopes.peek(); if (scopeRoots.isEmpty()) { return scope; } Iterator<Node> it = scopeRoots.descendingIterator(); while (it.hasNext()) { scope = scopeCreator.createScope(it.next(), scope); scopes.push(scope); } scopeRoots.clear(); return scope; } /** Gets the control flow graph for the current JS scope. */ public ControlFlowGraph<Node> getControlFlowGraph() { if (cfgs.peek() == null) { ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false); cfa.process(null, getScopeRoot()); cfgs.pop(); cfgs.push(cfa.getCfg()); } return cfgs.peek(); } /** Returns

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> the current scope's root. */ public Node getScopeRoot() { if (scopeRoots.isEmpty()) { return scopes.peek().getRootNode(); } else { return scopeRoots.peek(); } } /** * Determines whether the traversal is currently in the global scope. */ boolean inGlobalScope() { return getScopeDepth() <= 1; } int getScopeDepth() { return scopes.size() + scopeRoots.size(); } public boolean hasScope() { return !(scopes.isEmpty() && scopeRoots.isEmpty()); } /** Reports a diagnostic (error or warning) */ public void report(Node n, DiagnosticType diagnosticType, String... arguments) { JSError error = JSError.make(getSourceName(), n, diagnosticType, arguments); compiler.report(error); } private static String getSourceName(Node n) { String name = (String) n.getProp(Node.SOURCENAME_PROP); return name == null ? "" : name; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Remove this. public boolean flowSensitiveInlineVariables; /** Removes code associated with unused global names */ public boolean smartNameRemoval; /** Removes code that will never execute */ public boolean removeDeadCode; /** Checks for unreachable code */ public CheckLevel checkUnreachableCode; /** Checks for missing return statements */ public CheckLevel checkMissingReturn; /** Extracts common prototype member declarations */ public boolean extractPrototypeMemberDeclarations; /** Removes functions that have no body */ public boolean removeEmptyFunctions; /** Removes unused member prototypes */ public boolean removeUnusedPrototypeProperties; /** Tells AnalyzePrototypeProperties it can remove externed props. */ public boolean removeUnusedPrototypePropertiesInExterns; /** Removes unused variables */ public boolean removeUnusedVars; /** Removes unused variables in global scope. */ public boolean removeUnusedVarsInGlobalScope; /** Adds variable aliases for externals to reduce code size */ public boolean aliasExternals; /** * If set to a non-empty string, then during an alias externals pass only * externals with these names will be considered for aliasing. */ public String aliasableGlobals; /** * Additional globals that can not be aliased since they may be undefined or * can cause errors. Comma separated list of symbols. e.g. "foo,bar" */ public String unaliasableGlobals; /** Collapses multiple variable declarations into one */ public boolean collapseVariableDeclarations; /** * Collapses anonymous function declarations into named function * declarations */ public boolean collapseAnonymousFunctions; /** * If set to a non-empty set, those strings literals will be aliased to a * single global instance per string, to avoid creating more objects than * necessary. */ public Set<String> aliasableStrings; /** * A blacklist in the form of a regular expression to block strings that * contains certain words from being aliased. * If the value is the empty string, no words are blacklisted. */ public String aliasStringsBlacklist; /** * Aliases all string literals to global instances, to avoid creating more * objects than necessary (if true, overrides any set of strings passed in * to aliasableStrings) */ public boolean aliasAllStrings; /** Print string usage as part of the compilation

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> variable renaming map. */ public byte[] inputVariableMapSerialized; /** Serialized input property renaming map. */ public byte[] inputPropertyMapSerialized; /** Whether to export test functions. */ public boolean exportTestFunctions; //-------------------------------- // Special-purpose alterations //-------------------------------- /** Inserts runtime type assertions for debugging. */ boolean runtimeTypeCheck; /** * A JS function to be used for logging runtime type assertion * failures. It will be passed the warning as a string and the * faulty expression as arguments. */ String runtimeTypeCheckLogFunction; /** A CodingConvention to use during the compile. */ private CodingConvention codingConvention; /** Instrument code for the purpose of collecting coverage data. */ public boolean instrumentForCoverage; /** * Instrument code for the purpose of collecting coverage data - restrict to * coverage pass only, and skip all other passes. */ public boolean instrumentForCoverageOnly; /** Add code to skip properties that Caja adds to Object.prototype */ public boolean ignoreCajaProperties; public String syntheticBlockStartMarker; public String syntheticBlockEndMarker; /** Compiling locale */ public String locale; /** Sets the special "COMPILED" value to true */ public boolean markAsCompiled; /** Removes try...catch...finally blocks for easier debugging */ public boolean removeTryCatchFinally; /** Processes goog.provide() and goog.require() calls */ public boolean closurePass; /** Rewrite new Date(goog.now()) to new Date(). */ boolean rewriteNewDateGoogNow; /** Remove goog.abstractMethod assignments. */ boolean removeAbstractMethods; /** Gather CSS names (requires closurePass) */ public boolean gatherCssNames; /** Names of types to strip */ public Set<String> stripTypes; /** Name suffixes that determine which variables and properties to strip */ public Set<String> stripNameSuffixes; /** Name prefixes that determine which variables and properties to strip */ public Set<String> stripNamePrefixes; /** Qualified type name prefixes that determine which types to strip */ public Set<String> stripTypePrefixes; /** Custom passes */ public transient Multimap<CustomPassExecutionTime, CompilerPass> customPasses; /** Mark no side effect calls */ public boolean markNoSideEffectCalls; /** Replacement

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>s for @defines. Will be Boolean, Numbers, or Strings */ private Map<String, Object> defineReplacements; /** Move top level function declarations to the top */ public boolean moveFunctionDeclarations; /** Instrumentation template to use */ public String instrumentationTemplate; /** * App identifier string for use by the instrumentation template's * app_name_setter */ public String appNameStr; /** Record function information */ public boolean recordFunctionInformation; public boolean generateExports; /** Map used in the renaming of CSS class names. */ public CssRenamingMap cssRenamingMap; /** Process instances of goog.testing.ObjectPropertyString. */ boolean processObjectPropertyString; /** Id generators to replace. */ Set<String> idGenerators; //-------------------------------- // Output options //-------------------------------- /** Output in pretty indented format */ public boolean prettyPrint; /** Line break the output a bit more aggressively */ public boolean lineBreak; /** Prints a separator comment before each js script */ public boolean printInputDelimiter; /** The string to use as the separator for printInputDelimiter */ public String inputDelimiter = "// Input %num%"; /** Where to save a report of global name usage */ public String reportPath; public TracerMode tracer; private boolean colorizeErrorOutput; public ErrorFormat errorFormat; public String jsOutputFile; private transient ComposeWarningsGuard warningsGuard; //-------------------------------- // Special Output Options //-------------------------------- /** The output path for the created externs file. */ String externExportsPath; /** Where to save a cross-reference report from the name reference graph */ public String nameReferenceReportPath; /** Where to save the name reference graph */ public String nameReferenceGraphPath; //-------------------------------- // Debugging Options //-------------------------------- /** The output path for the source map. */ public String sourceMapOutputPath; /** * Charset to use when generating code. If null, then output ASCII. */ public Charset outputCharset; /** * Initializes compiler options. All options are disabled by default. * * Command-line frontends to the compiler should set these properties * like a builder. */ public CompilerOptions() { // Checks skipAllPasses = false; nameAnonymousFunctionsOnly = false; devMode = DevMode

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> given type of warning to the given level. */ public void setWarningLevel(DiagnosticGroup type, CheckLevel level) { addWarningsGuard(new DiagnosticGroupWarningsGuard(type, level)); } WarningsGuard getWarningsGuard() { return warningsGuard; } /** * Add a guard to the set of warnings guards. */ public void addWarningsGuard(WarningsGuard guard) { if (warningsGuard == null) { warningsGuard = new ComposeWarningsGuard(guard); } else { warningsGuard.addGuard(guard); } } /** * Sets the variable and property renaming policies for the compiler, * in a way that clears warnings about the renaming policy being * uninitialized from flags. */ public void setRenamingPolicy(VariableRenamingPolicy newVariablePolicy, PropertyRenamingPolicy newPropertyPolicy) { this.variableRenaming = newVariablePolicy; this.propertyRenaming = newPropertyPolicy; } /** * If true, flattens multi-level property names on extern types * (e.g. String$f = x). This should only be used with the typed version of * the externs files. */ public void setCollapsePropertiesOnExternTypes(boolean collapse) { collapsePropertiesOnExternTypes = collapse; } /** * If true, process goog.testing.ObjectPropertyString instances. */ public void setProcessObjectPropertyString(boolean process) { processObjectPropertyString = process; } /** * Sets the id generators to replace. */ public void setIdGenerators(Set<String> idGenerators) { this.idGenerators = Sets.newHashSet(idGenerators); } public void setRewriteNewDateGoogNow(boolean rewrite) { this.rewriteNewDateGoogNow = rewrite; } public void setRemoveAbstractMethods(boolean remove) { this.removeAbstractMethods = remove; } /** * If true, name anonymous functions only. All other passes will be skipped. */ public void setNameAnonymousFunctionsOnly(boolean value) { this.nameAnonymousFunctionsOnly = value; } public void setColorizeErrorOutput(boolean colorizeErrorOutput) { this.colorizeErrorOutput = colorizeErrorOutput; } public boolean shouldColorizeErrorOutput()

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isStringValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "string"; } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.STRING_OBJECT_TYPE); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseStringType(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> ObjToIntMap implements Serializable { static final long serialVersionUID = -1542220580748809402L; // Map implementation via hashtable, // follows "The Art of Computer Programming" by Donald E. Knuth // ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys public static class Iterator { Iterator(ObjToIntMap master) { this.master = master; } final void init(Object[] keys, int[] values, int keyCount) { this.keys = keys; this.values = values; this.cursor = -1; this.remaining = keyCount; } public void start() { master.initIterator(this); next(); } public boolean done() { return remaining < 0; } public void next() { if (remaining == -1) Kit.codeBug(); if (remaining == 0) { remaining = -1; cursor = -1; }else { for (++cursor; ; ++cursor) { Object key = keys[cursor]; if (key != null && key != DELETED) { --remaining; break; } } } } public Object getKey() { Object key = keys[cursor]; if (key == UniqueTag.NULL_VALUE) { key = null; } return key; } public int getValue() { return values[cursor]; } public void setValue(int value) { values[cursor] = value; } ObjToIntMap master; private int cursor; private int remaining; private Object[] keys; private int[] values; } public ObjToIntMap() { this(4); } public ObjToIntMap(int keyCountHint) { if (keyCountHint < 0) Kit.codeBug(); // Table grow when number of stored keys >= 3/4 of max capacity int minimalCapacity = keyCountHint * 4 / 3; int i; for (i = 2; (1 << i) < minimalCapacity; ++i) { } power = i; if (check && power < 2) Kit.codeBug(); } public boolean isEmpty() { return key

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Count == 0; } public int size() { return keyCount; } public boolean has(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } return 0 <= findIndex(key); } /** * Get integer value assigned with key. * @return key integer value or defaultValue if key is absent */ public int get(Object key, int defaultValue) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { return values[index]; } return defaultValue; } /** * Get integer value assigned with key. * @return key integer value * @throws RuntimeException if key does not exist */ public int getExisting(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { return values[index]; } // Key must exist Kit.codeBug(); return 0; } public void put(Object key, int value) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = ensureIndex(key); values[index] = value; } /** * If table already contains a key that equals to keyArg, return that key * while setting its value to zero, otherwise add keyArg with 0 value to * the table and return it. */ public Object intern(Object keyArg) { boolean nullKey = false; if (keyArg == null) { nullKey = true; keyArg = UniqueTag.NULL_VALUE; } int index = ensureIndex(keyArg); values[index] = 0; return (nullKey) ? null : keys[index]; } public void remove(Object key) { if (key == null) { key = UniqueTag.NULL_VALUE; } int index = findIndex(key); if (0 <= index) { keys[index] = DELETED; --keyCount; } } public void clear() { int i = keys.length; while (i != 0) { keys

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>[--i] = null; } keyCount = 0; occupiedCount = 0; } public Iterator newIterator() { return new Iterator(this); } // The sole purpose of the method is to avoid accessing private fields // from the Iterator inner class to workaround JDK 1.1 compiler bug which // generates code triggering VerifierError on recent JVMs final void initIterator(Iterator i) { i.init(keys, values, keyCount); } /** Return array of present keys */ public Object[] getKeys() { Object[] array = new Object[keyCount]; getKeys(array, 0); return array; } public void getKeys(Object[] array, int offset) { int count = keyCount; for (int i = 0; count != 0; ++i) { Object key = keys[i]; if (key != null && key != DELETED) { if (key == UniqueTag.NULL_VALUE) { key = null; } array[offset] = key; ++offset; --count; } } } private static int tableLookupStep(int fraction, int mask, int power) { int shift = 32 - 2 * power; if (shift >= 0) { return ((fraction >>> shift) & mask) | 1; } else { return (fraction & (mask >>> -shift)) | 1; } } private int findIndex(Object key) { if (keys != null) { int hash = key.hashCode(); int fraction = hash * A; int index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } } } } return -1; } // Insert key that is not present to table without deleted entries // and enough free space private int insertNewKey(Object key, int hash) { if (check && occupiedCount != keyCount) Kit.codeBug(); if (check && keyCount == 1 << power) Kit.codeBug(); int fraction = hash * A; int index = fraction >>> (32 - power); int N = 1 << power; if (keys[index] != null) { int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int firstIndex = index; do { if (check && keys[index] == DELETED) Kit.codeBug(); index = (index + step) & mask; if (check && firstIndex == index) Kit.codeBug(); } while (keys[index] != null); } keys[index] = key; values[N + index] = hash; ++occupiedCount; ++keyCount; return index; } private void rehashTable() { if (keys == null) { if (check && keyCount != 0) Kit.codeBug(); if (check && occupiedCount != 0) Kit.codeBug(); int N = 1 << power; keys = new Object[N]; values = new int[2 * N]; } else { // Check if removing deleted entries would free enough space if (keyCount * 2 >= occupiedCount) { // Need to grow: less then half of deleted entries ++power; } int N = 1 << power; Object[] oldKeys = keys; int[] oldValues = values; int oldN = oldKeys.length; keys = new Object[N]; values = new int[2 * N]; int remaining = keyCount; occupiedCount = keyCount = 0; for (int i = 0; remaining != 0; ++i) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Object key = oldKeys[i]; if (key != null && key != DELETED) { int keyHash = oldValues[oldN + i]; int index = insertNewKey(key, keyHash); values[index] = oldValues[i]; --remaining; } } } } // Ensure key index creating one if necessary private int ensureIndex(Object key) { int hash = key.hashCode(); int index = -1; int firstDeleted = -1; if (keys != null) { int fraction = hash * A; index = fraction >>> (32 - power); Object test = keys[index]; if (test != null) { int N = 1 << power; if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED) { firstDeleted = index; } // Search in table after first failed attempt int mask = N - 1; int step = tableLookupStep(fraction, mask, power); int n = 0; for (;;) { if (check) { if (n >= occupiedCount) Kit.codeBug(); ++n; } index = (index + step) & mask; test = keys[index]; if (test == null) { break; } if (test == key || (values[N + index] == hash && test.equals(key))) { return index; } if (test == DELETED && firstDeleted < 0) { firstDeleted = index; } } } } // Inserting of new key if (check && keys != null && keys[index] != null) Kit.codeBug(); if (firstDeleted >= 0) { index = firstDeleted; } else { // Need to consume empty entry: check occupation level if (keys == null || occupiedCount * 4 >= (1 << power) * 3) { // Too litle unused entries: rehash rehashTable(); return insertNewKey(key, hash); } ++occupiedCount; } keys[index] = key; values[(1 << power) +

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Lists; import com.google.javascript.jscomp.CheckLevel; import java.util.*; /** * WarningsGuard that represents just a chain of other guards. For example we * could have following chain * 1) all warnings outside of /foo/ should be suppressed * 2) errors with key JSC_BAR should be marked as warning * 3) the rest should be reported as error * * This class is designed for such behaviour. * * */ public class ComposeWarningsGuard extends WarningsGuard { private final List<WarningsGuard> guards; private static final Comparator<WarningsGuard> guardComparator = new Comparator<WarningsGuard>() { @Override public int compare(WarningsGuard a, WarningsGuard b) { return a.getPriority() - b.getPriority(); } }; public ComposeWarningsGuard(List<WarningsGuard> guards) { this.guards = Lists.newArrayList(); addGuards(guards); } public ComposeWarningsGuard(WarningsGuard... guards) { this(Lists.newArrayList(guards)); } void addGuard(WarningsGuard guard) { if (guard instanceof ComposeWarningsGuard) { addGuards(((ComposeWarningsGuard) guard).guards); } else { int index = Collections.binarySearch(this.guards, guard, guardComparator); if (index < 0) { index = -index - 1; } this.guards.add(index, guard); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> private void addGuards(Iterable<WarningsGuard> guards) { for (WarningsGuard guard : guards) { addGuard(guard); } } @Override public CheckLevel level(JSError error) { for (WarningsGuard guard : guards) { CheckLevel newLevel = guard.level(error); if (newLevel != null) { return newLevel; } } return null; } @Override public boolean disables(DiagnosticGroup group) { nextSingleton: for (DiagnosticType type : group.getTypes()) { DiagnosticGroup singleton = DiagnosticGroup.forType(type); for (WarningsGuard guard : guards) { if (guard.disables(singleton)) { continue nextSingleton; } else if (guard.enables(singleton)) { return false; } } return false; } return true; } /** * Determines whether this guard will "elevate" the status of any disabled * diagnostic type in the group to a warning or an error. */ @Override public boolean enables(DiagnosticGroup group) { for (WarningsGuard guard : guards) { if (guard.enables(group)) { return true; } } return false; } List<WarningsGuard> getGuards() { return Collections.unmodifiableList(guards); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(); // Save the tree for later comparison. Node rootClone = root.cloneTree(); Node externsRootClone = rootClone.getFirstChild(); Node mainRootClone = rootClone.getLastChild(); int numRepetitions = getNumRepetitions(); ErrorManager[] errorManagers = new ErrorManager[numRepetitions]; int aggregateWarningCount = 0; List<JSError> aggregateWarnings = Lists.newArrayList(); boolean hasCodeChanged = false; assertFalse("Code should not change before processing", recentChange.hasCodeChanged()); for (int i = 0; i < numRepetitions; ++i) { if (compiler.getErrorCount() == 0) { errorManagers[i] = new BlackHoleErrorManager(compiler); // Only run the type checking pass once, if asked. // Running it twice can cause unpredictable behavior because duplicate // objects for the same type are created, and the type system // uses reference equality to compare many types. if (typeCheckEnabled && i == 0) { TypeCheck check = createTypeCheck(compiler, typeCheckLevel); check.processForTesting(externsRoot, mainRoot); } // Only run the normalize pass once, if asked. if (normalizeEnabled && i == 0) { Normalize normalize = new Normalize(compiler, false); normalize.process(externsRoot, mainRoot); compiler.setNormalized(); } if (markNoSideEffects && i == 0) { MarkNoSideEffectCalls mark = new MarkNoSideEffectCalls(compiler); mark.process(externsRoot, mainRoot); } recentChange.reset(); getProcessor(compiler).process(externsRoot, mainRoot); if (checkLineNumbers) { (new LineNumberCheck(compiler)).process(externsRoot, mainRoot); } hasCodeChanged = hasCodeChanged || recentChange.hasCodeChanged(); aggregateWarningCount += errorManagers[i].getWarningCount(); aggregateWarnings.addAll(Lists.newArrayList(compiler.getWarnings())); if (normalizeEnabled) { boolean verifyDeclaredConstants = true; new Normalize.VerifyConstants(compiler, verifyDeclaredConstants) .process(externsRoot, mainRoot); } } } if (error == null) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> */ static JSModule[] createModules(String... inputs) { JSModule[] modules = new JSModule[inputs.length]; for (int i = 0; i < inputs.length; i++) { JSModule module = modules[i] = new JSModule("m" + i); module.add(JSSourceFile.fromCode("i" + i, inputs[i])); } return modules; } private static class BlackHoleErrorManager extends BasicErrorManager { private BlackHoleErrorManager(Compiler compiler) { compiler.setErrorManager(this); } @Override public void println(CheckLevel level, JSError error) {} @Override public void printSummary() {} } private Compiler createCompiler() { Compiler compiler = new Compiler(); return compiler; } protected void setExpectedSymbolTableError(DiagnosticType type) { this.expectedSymbolTableError = type; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Sets; import com.google.javascript.jscomp.CheckLevel; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.SortedSet; /** * <p>A basic error manager that sorts all errors and warnings reported to it to * generate a sorted report when the {@link #generateReport()} method * is called.</p> * * <p>This error manager does not produce any output, but subclasses can * override the {@link #println(CheckLevel, JSError)} method to generate custom * output.</p> * * * */ public abstract class BasicErrorManager implements ErrorManager { private final SortedSet<ErrorWithLevel> messages = Sets.newTreeSet(new LeveledJSErrorComparator()); private int errorCount = 0; private int warningCount = 0; private double typedPercent = 0.0; public void report(CheckLevel level, JSError error) { if (messages.add(new ErrorWithLevel(error, level))) { if (level == CheckLevel.ERROR) { errorCount++; } else if (level == CheckLevel.WARNING) { warningCount++; } } } public void generateReport() { for (ErrorWithLevel message : messages) { println(message.level, message.error); } printSummary(); } /** * Print a message with a trailing new line. This method is called by the * {@link #generate

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Report()} method when generating messages. */ public abstract void println(CheckLevel level, JSError error); /** * Print the summary of the compilation - number of errors and warnings. */ protected abstract void printSummary(); public int getErrorCount() { return errorCount; } public int getWarningCount() { return warningCount; } public JSError[] getErrors() { return toArray(CheckLevel.ERROR); } public JSError[] getWarnings() { return toArray(CheckLevel.WARNING); } public void setTypedPercent(double typedPercent) { this.typedPercent = typedPercent; } public double getTypedPercent() { return typedPercent; } private JSError[] toArray(CheckLevel level) { List<JSError> errors = new ArrayList<JSError>(messages.size()); for (ErrorWithLevel p : messages) { if (p.level == level) { errors.add(p.error); } } return errors.toArray(new JSError[errors.size()]); } /** * <p>Comparator of {@link JSError} with an associated {@link CheckLevel}. * The ordering is the standard lexical ordering on the quintuple * (file name, line number, {@link CheckLevel}, * character number, description).</p> * * <p>Note: this comparator imposes orderings that are inconsistent with * {@link JSError#equals(Object)}.</p> */ static final class LeveledJSErrorComparator implements Comparator<ErrorWithLevel> { private static final int P1_LT_P2 = -1; private static final int P1_GT_P2 = 1; public int compare(ErrorWithLevel p1, ErrorWithLevel p2) { // null is the smallest value if (p2 == null) { if (p1 == null) { return 0; } else { return P1_GT_P2; } } // check level if (p1.level != p2.level) { return p2.level.compareTo(p1.level); } // sourceName comparison String source1 = p1.error.sourceName; String source2

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>int i = 0; i != N; ++i) { Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public int lastIndexOf(Object obj) { for (int i = size; i != 0;) { --i; Object current = getImpl(i); if (current == obj || (current != null && current.equals(obj))) { return i; } } return -1; } public final Object peek() { int N = size; if (N == 0) throw onEmptyStackTopRead(); return getImpl(N - 1); } @SuppressWarnings("fallthrough") public final Object pop() { if (sealed) throw onSeledMutation(); int N = size; --N; Object top; switch (N) { case -1: throw onEmptyStackTopRead(); case 0: top = f0; f0 = null; break; case 1: top = f1; f1 = null; break; case 2: top = f2; f2 = null; break; case 3: top = f3; f3 = null; break; case 4: top = f4; f4 = null; break; default: top = data[N - FIELDS_STORE_SIZE]; data[N - FIELDS_STORE_SIZE] = null; } size = N; return top; } public final void push(Object value) { add(value); } public final void add(Object value) { if (sealed) throw onSeledMutation(); int N = size; if (N >= FIELDS_STORE_SIZE) { ensureCapacity(N + 1); } size = N + 1; setImpl(N, value); } @SuppressWarnings("fallthrough") public final void add(int index, Object value) { int N = size; if (!(0 <= index && index <= N)) throw onInvalidIndex(index, N + 1); if (sealed) throw onSeledMutation(); Object

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> tmp; switch (index) { case 0: if (N == 0) { f0 = value; break; } tmp = f0; f0 = value; value = tmp; case 1: if (N == 1) { f1 = value; break; } tmp = f1; f1 = value; value = tmp; case 2: if (N == 2) { f2 = value; break; } tmp = f2; f2 = value; value = tmp; case 3: if (N == 3) { f3 = value; break; } tmp = f3; f3 = value; value = tmp; case 4: if (N == 4) { f4 = value; break; } tmp = f4; f4 = value; value = tmp; index = FIELDS_STORE_SIZE; default: ensureCapacity(N + 1); if (index != N) { System.arraycopy(data, index - FIELDS_STORE_SIZE, data, index - FIELDS_STORE_SIZE + 1, N - index); } data[index - FIELDS_STORE_SIZE] = value; } size = N + 1; } @SuppressWarnings("fallthrough") public final void remove(int index) { int N = size; if (!(0 <= index && index < N)) throw onInvalidIndex(index, N); if (sealed) throw onSeledMutation(); --N; switch (index) { case 0: if (N == 0) { f0 = null; break; } f0 = f1; case 1: if (N == 1) { f1 = null; break; } f1 = f2; case 2: if (N == 2) { f2 = null; break; } f2 = f3; case 3: if (N == 3) { f3 = null; break; } f3 = f4; case 4: if (N == 4) { f4 = null; break; } f4 = data[0]; index = FIELDS_STORE_SIZE;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Native. private final boolean isChecked; UnknownType(JSTypeRegistry registry, boolean isChecked) { super(registry); this.isChecked = isChecked; } @Override public boolean isUnknownType() { return true; } @Override public boolean isCheckedUnknownType() { return isChecked; } @Override public boolean canAssignTo(JSType that) { return true; } @Override public boolean canBeCalled() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public TernaryValue testForEquality(JSType that) { return UNKNOWN; } @Override public boolean isNullable() { return true; } @Override public boolean isSubtype(JSType that) { return true; } @Override public JSType getLeastSupertype(JSType that) { return this; } @Override public JSType getGreatestSubtype(JSType that) { return this; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnknownType(); } @Override public String toString() { return getReferenceName(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { // nothing to define return true; } @Override public ObjectType getImplicitPrototype() { return null; } @Override public int getPropertiesCount() { return Integer.MAX_VALUE; } @Override protected void collectPropertyNames(Set<String> props) { } @Override public JSType getPropertyType(String propertyName) { return this; } @Override public boolean hasProperty(String propertyName) { return true; } @Override public FunctionType getConstructor() { return null; } @Override public String getReferenceName() { return isChecked ? "??" : "?"; } @Override public boolean isPropertyTypeDeclared(String propertyName) { return false; } @

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.Iterables; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; /** * A {@link JSModule} dependency graph that assigns a depth to each module and * can answer depth-related queries about them. For the purposes of this class, * a module's depth is defined as the number of hops in the longest path from * the module to a module with no dependencies. * * */ public class JSModuleGraph { /** * Map from a module to its depth. */ private Map<JSModule, Integer> moduleDepths; /** * Lists of modules at each depth. <code>modulesByDepth.get(3)</code> is a * list of the modules at depth 3, for example. */ private List<List<JSModule>> modulesByDepth; /** * dependencyMap is a cache of dependencies that makes the dependsOn * function faster. Each map entry associates a starting * JSModule with the set of JSModules that are transitively dependent on the * starting module. * * If the cache returns null, then the entry hasn

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>'t been filled in for that * module. * * dependencyMap should be filled from leaf to root so that * getTransitiveDepsDeepestFirst can use its results directly. */ private Map<JSModule, Set<JSModule>> dependencyMap = Maps.newHashMap(); /** * Creates a module graph from a list of modules in dependency order. */ public JSModuleGraph(JSModule[] modulesInDepOrder) { moduleDepths = new HashMap<JSModule, Integer>(modulesInDepOrder.length); modulesByDepth = new ArrayList<List<JSModule>>(); for (JSModule module : modulesInDepOrder) { int depth = 0; for (JSModule dep : module.getDependencies()) { Integer depDepth = moduleDepths.get(dep); if (depDepth == null) { throw new ModuleDependenceException(String.format( "Modules not in dependency order: %s preceded %s", module.getName(), dep.getName()), module, dep); } depth = Math.max(depth, depDepth + 1); } moduleDepths.put(module, depth); if (depth == modulesByDepth.size()) { modulesByDepth.add(new ArrayList<JSModule>()); } modulesByDepth.get(depth).add(module); } } /** * Gets an iterable over all modules. */ Iterable<JSModule> getAllModules() { return moduleDepths.keySet(); } /** * Gets the total number of modules. */ int getModuleCount() { return moduleDepths.size(); } /** * Gets the root module. */ JSModule getRootModule() { return Iterables.getOnlyElement(modulesByDepth.get(0)); } /** * Gets the depth of a module. * * @param module A module in this graph * @return The depth of the module */ int getDepth(JSModule module) { return moduleDepths.get(module); } /** * Determines whether this module depends on a given module. Note that a * module never depends on itself, as that dependency would be cyclic. */ public boolean dependsOn(JSModule src, JSModule m) { Set

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS><JSModule> deps = dependencyMap.get(src); if (deps == null) { deps = getTransitiveDepsDeepestFirst(src); dependencyMap.put(src, deps); } return deps.contains(m); } /** * Finds the deepest common dependency of two modules, not including the two * modules themselves. * * @param m1 A module in this graph * @param m2 A module in this graph * @return The deepest common dep of {@code m1} and {@code m2}, or null if * they have no common dependencies */ JSModule getDeepestCommonDependency(JSModule m1, JSModule m2) { int m1Depth = getDepth(m1); int m2Depth = getDepth(m2); // According our definition of depth, the result must have a strictly // smaller depth than either m1 or m2. for (int depth = Math.min(m1Depth, m2Depth) - 1; depth >= 0; depth--) { List<JSModule> modulesAtDepth = modulesByDepth.get(depth); // Look at the modules at this depth in reverse order, so that we use the // original ordering of the modules to break ties (later meaning deeper). for (int i = modulesAtDepth.size() - 1; i >= 0; i--) { JSModule m = modulesAtDepth.get(i); if (dependsOn(m1, m) && dependsOn(m2, m)) { return m; } } } return null; } /** * Finds the deepest common dependency of two modules, including the * modules themselves. * * @param m1 A module in this graph * @param m2 A module in this graph * @return The deepest common dep of {@code m1} and {@code m2}, or null if * they have no common dependencies */ public JSModule getDeepestCommonDependencyInclusive( JSModule m1, JSModule m2) { if (m2 == m1 || dependsOn(m2, m1)) { return m1; } else if (dependsOn(m1, m2

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>)) { return m2; } return getDeepestCommonDependency(m1, m2); } /** Returns the deepest common dependency of the given modules. */ public JSModule getDeepestCommonDependencyInclusive( Collection<JSModule> modules) { Iterator<JSModule> iter = modules.iterator(); JSModule dep = iter.next(); while (iter.hasNext()) { dep = getDeepestCommonDependencyInclusive(dep, iter.next()); } return dep; } /** * Creates an iterable over the transitive dependencies of module {@code m} * in a non-increasing depth ordering. The result does not include the module * {@code m}. * * @param m A module in this graph * @return The transitive dependencies of module {@code m} */ Set<JSModule> getTransitiveDepsDeepestFirst(JSModule m) { Set<JSModule> deps = dependencyMap.get(m); if (deps != null) { return deps; } deps = new TreeSet<JSModule>(new InverseDepthComparator()); addDeps(deps, m); dependencyMap.put(m, deps); return deps; } /** * Adds a module's transitive dependencies to a set. */ private void addDeps(Set<JSModule> deps, JSModule m) { for (JSModule dep : m.getDependencies()) { deps.add(dep); addDeps(deps, dep); } } /** * Replaces any files that are found multiple times with a single instance in * the closest parent module that is common to all modules where it appears. * * JSCompiler normally errors if you attempt to compile modules containing the * same file. This method can be used to remove duplicates before compiling * to avoid such an error. */ public void coalesceDuplicateFiles() { Multimap<String, JSModule> fileRefs = LinkedHashMultimap.create(); for (JSModule module : moduleDepths.keySet()) { for (CompilerInput jsFile : module.getInputs()) { fileRefs.put(jsFile.getName(), module); } } for (String path : fileRefs.keySet()) { Collection<JSModule> ref

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Modules = fileRefs.get(path); if (refModules.size() > 1) { JSModule depModule = getDeepestCommonDependencyInclusive(refModules); CompilerInput file = refModules.iterator().next().getByName(path); for (JSModule module : refModules) { if (module != depModule) { module.removeByName(path); } } if (!refModules.contains(depModule)) { depModule.add(file); } } } } /** * A module depth comparator that considers a deeper module to be "less than" * a shallower module. Uses module names to consistently break ties. */ private class InverseDepthComparator implements Comparator<JSModule> { public int compare(JSModule m1, JSModule m2) { if (m1 == m2) { return 0; } int d1 = getDepth(m1); int d2 = getDepth(m2); return d2 < d1 ? -1 : d2 == d1 ? m2.getName().compareTo(m1.getName()) : 1; } } /* * Exception class for declaring when the modules being fed into a * JSModuleGraph as input aren't in dependence order, and so can't be * processed for caching of various dependency-related queries. */ protected static class ModuleDependenceException extends IllegalArgumentException { private static final long serialVersionUID = 1; private final JSModule module; private final JSModule dependentModule; protected ModuleDependenceException(String message, JSModule module, JSModule dependentModule) { super(message); this.module = module; this.dependentModule = dependentModule; } public JSModule getModule() { return module; } public JSModule getDependentModule() { return dependentModule; } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>IN_EXTERNS_ERROR = DiagnosticType.warning( "JSC_NAME_REFERENCE_IN_EXTERNS", "accessing name {0} in externs has no effect"); static final DiagnosticType INVALID_FUNCTION_DECL = DiagnosticType.error("JSC_INVALID_FUNCTION_DECL", "Syntax error: function declaration must have a name"); private CompilerInput synthesizedExternsInput = null; private Node synthesizedExternsRoot = null; private final AbstractCompiler compiler; // Whether this is the post-processing sanity check. private final boolean sanityCheck; VarCheck(AbstractCompiler compiler) { this(compiler, false); } VarCheck(AbstractCompiler compiler, boolean sanityCheck) { this.compiler = compiler; this.sanityCheck = sanityCheck; } /** {@inheritDoc} */ public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, externs, new NameRefInExternsCheck()); NodeTraversal.traverseRoots( compiler, Lists.newArrayList(externs, root), this); } /** {@inheritDoc} */ public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() != Token.NAME) { return; } if (NodeUtil.isLabelName(n)) { return; } String varName = n.getString(); // Only a function can have an empty name. if (varName.isEmpty()) { Preconditions.checkState(NodeUtil.isFunction(parent)); // A function declaration with an empty name passes Rhino, // but is supposed to be a syntax error according to the spec. if (!NodeUtil.isAnonymousFunction(parent)) { t.report(n, INVALID_FUNCTION_DECL); } return; } // Check that the var has been declared. Scope scope = t.getScope(); Scope.Var var = scope.getVar(varName); if (var == null) { if (NodeUtil.isAnonymousFunction(parent)) { // e.g. [ function foo() {} ], it's okay if "foo" isn't defined in the // current scope. } else { t.report(n, UNDEFINED_VAR_ERROR, varName); if

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (sanityCheck) { throw new IllegalStateException("Unexpected variable " + varName); } else { // Create a new variable in a synthetic script. This will prevent // subsequent compiler passes from crashing. Node nameNode = Node.newString(Token.NAME, varName); getSynthesizedExternsRoot().addChildToBack( new Node(Token.VAR, nameNode)); scope.getGlobalScope().declare(varName, nameNode, null, getSynthesizedExternsInput()); } } return; } CompilerInput currInput = t.getInput(); CompilerInput varInput = var.input; if (currInput == varInput || currInput == null || varInput == null) { // The variable was defined in the same file. This is fine. return; } // Check module dependencies. JSModule currModule = currInput.getModule(); JSModule varModule = varInput.getModule(); JSModuleGraph moduleGraph = compiler.getModuleGraph(); if (varModule != currModule && varModule != null && currModule != null) { if (moduleGraph.dependsOn(currModule, varModule)) { // The module dependency was properly declared. } else { if (!sanityCheck && scope.isGlobal()) { if (moduleGraph.dependsOn(varModule, currModule)) { // The variable reference violates a declared module dependency. t.report(n, VIOLATED_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } else { // The variable reference is between two modules that have no // dependency relationship. This should probably be considered an // error, but just issue a warning for now. t.report(n, MISSING_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } else { t.report(n, STRICT_MODULE_DEP_ERROR, currModule.getName(), varModule.getName(), varName); } } } } /** * A check for name references in the externs inputs. These used to prevent * a variable from getting renamed, but no longer have any effect. */ private class NameRefInExternsCheck extends AbstractPostOrderCallback { public void visit(

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { private static final long serialVersionUID = 1L; VoidType(JSTypeRegistry registry) { super(registry); } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isSubtype(this) || that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) { return TRUE; } return FALSE; } @Override public boolean matchesNumberContext() { return false; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public boolean isVoidType() { return true; } @Override public String toString() { return "undefined"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseVoidType(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2005 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * A JavaScript module has a unique name, consists of a list of compiler inputs, * and can depend on other modules. * * * */ public class JSModule { /** Module name */ private final String name; /** Source code inputs */ private final List<CompilerInput> inputs = new ArrayList<CompilerInput>(); /** Modules that this module depends on */ private final List<JSModule> deps = new ArrayList<JSModule>(); /** * Creates an instance. * * @param name A unique name for the module */ public JSModule(String name) { this.name = name; } /** Gets the module name. */ public String getName() { return name; } /** Adds a source file input to this module. */ public void add(JSSourceFile file) { add(new CompilerInput(file)); } /** Adds a source file input to this module. */ public void addFirst(JSSourceFile file) { addFirst(new CompilerInput(file)); } /** Adds a source code input to this module. */ public void add(CompilerInput input) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> inputs.add(input); input.setModule(this); } /** Adds a source code input to this module. */ public void addFirst(CompilerInput input) { inputs.add(0, input); input.setModule(this); } /** Adds a source code input to this module directly after other. */ public void addAfter(CompilerInput input, CompilerInput other) { Preconditions.checkState(inputs.contains(other)); inputs.add(inputs.indexOf(other), input); input.setModule(this); } /** Adds a dependency on another module. */ public void addDependency(JSModule dep) { Preconditions.checkState(dep != this); deps.add(dep); } /** Removes all of the inputs from this module. */ public void removeAll() { for (CompilerInput input : inputs) { input.setModule(null); } inputs.clear(); } /** * Gets the list of modules that this module depends on. * * @return A list that may be empty but not null */ public List<JSModule> getDependencies() { return deps; } /** * Returns the transitive closure of dependencies starting from the * dependencies of this module. */ public Set<JSModule> getAllDependencies() { Set<JSModule> allDeps = Sets.newHashSet(deps); List<JSModule> workList = Lists.newArrayList(deps); while (workList.size() > 0) { JSModule module = workList.remove(workList.size() - 1); for (JSModule dep : module.getDependencies()) { if (allDeps.add(dep)) { workList.add(dep); } } } return allDeps; } /** Returns this module and all of its dependencies in one list. */ public Set<JSModule> getThisAndAllDependencies() { Set<JSModule> deps = getAllDependencies(); deps.add(this); return deps; } /** * Gets this module's list of source code inputs. * * @return A list that may be empty but not null */ public List<CompilerInput> getInputs() { return inputs; } /** Returns the input with the

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> given name or null if none. */ public CompilerInput getByName(String name) { for (CompilerInput input : inputs) { if (name.equals(input.getName())) { return input; } } return null; } /** * Removes any input with the given name. Returns whether any were removed. */ public boolean removeByName(String name) { boolean found = false; Iterator<CompilerInput> iter = inputs.iterator(); while (iter.hasNext()) { CompilerInput file = iter.next(); if (name.equals(file.getName())) { iter.remove(); file.setModule(null); found = true; } } return found; } /** Returns the module name (primarily for debugging). */ @Override public String toString() { return name; } /** * Removes any references to nodes of the AST. This method is needed to * allow the ASTs to be garbage collected if the modules are kept around. */ public void clearAsts() { for (CompilerInput input : inputs) { input.clearAst(); } } /** * Puts the JS files into a topologically sorted order by their dependencies. */ public void sortInputsByDeps(Compiler compiler) { // Collect all symbols provided in these files. final Map<String, CompilerInput> provides = Maps.newHashMap(); for (CompilerInput input : inputs) { for (String provide : input.getProvides(compiler)) { provides.put(provide, input); } } // Put the files into topologically sorted order by their requires. // NOTE: This will leave the list unchanged if the files are already // topologically sorted. This is important to apps whose dependencies // are incomplete. List<CompilerInput> list = Lists.newArrayList(); Set<CompilerInput> set = Sets.newHashSet(); for (CompilerInput input : inputs) { addInputAndDeps(input, provides, compiler, list, set, Sets.<CompilerInput>newHashSet()); } // Update the JSModule to this order. Preconditions.checkState(inputs.size() == list.size()); inputs.clear(); inputs.addAll(list); } /** *

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Returns the given collection of modules in topological order. * * Note that this will return the modules in the same order if they are * already sorted, and in general, will only change the order as necessary to * satisfy the ordering dependencies. This can be important for cases where * the modules do not properly specify all dependencies. */ public static JSModule[] sortJsModules(Collection<JSModule> modules) { List<JSModule> list = Lists.newArrayList(); Set<JSModule> set = Sets.newHashSet(); for (JSModule module : modules) { addModuleAndDeps(module, list, set, Sets.<JSModule>newHashSet()); } return list.toArray(new JSModule[list.size()]); } /** * Adds the given input and its deps to the given list and set, if they are * not already added, placing dependencies before dependants. */ private static void addInputAndDeps( CompilerInput input, Map<String, CompilerInput> provides, Compiler compiler, List<CompilerInput> list, Set<CompilerInput> set, Set<CompilerInput> inProgress) { if (!set.contains(input)) { if (inProgress.contains(input)) { throw new IllegalArgumentException( "Circular dependency involving input: " + input.getName()); } inProgress.add(input); for (String require : input.getRequires(compiler)) { if (provides.containsKey(require)) { addInputAndDeps(provides.get(require), provides, compiler, list, set, inProgress); } } list.add(input); set.add(input); } } /** * Adds the given module and its deps to the given list and set, if they are * not already added, placing dependencies before dependants. */ private static void addModuleAndDeps( JSModule module, List<JSModule> list, Set<JSModule> set, Set<JSModule> inProgress) { if (!set.contains(module)) { if (inProgress.contains(module)) { throw new IllegalArgumentException( "Circular dependency involving module: " + module.getName()); } inProgress.add(module); for (JSModule dep : module.getDependencies()) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> addModuleAndDeps(dep, list, set, inProgress); } list.add(module); set.add(module); } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> qualifiedName = node.getQualifiedName(); Preconditions.checkNotNull(qualifiedName); JSType origType = node.getJSType(); origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType; scope.inferQualifiedSlot(qualifiedName, origType, type); break; default: throw new IllegalArgumentException("Node cannot be refined."); } } /** * @see #getRestrictedWithoutUndefined(JSType) */ private final Visitor<JSType> restrictUndefinedVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType) { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(VOID_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return null; } }; /** * @see #getRestrictedWithoutNull(JSType) */ private final Visitor<JSType> restrictNullVisitor = new Visitor<JSType>() { public JSType caseEnumElementType(EnumElementType enumElementType)

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } public JSType caseAllType() { return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE); } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseUnionType(UnionType type) { return type.getRestrictedUnion(getNativeType(NULL_TYPE)); } public JSType caseUnknownType() { return getNativeType(UNKNOWN_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } }; /** * A class common to all visitors that need to restrict the type based on * {@code typeof}-like conditions. */ abstract class RestrictByTypeOfResultVisitor implements Visitor<JSType> { /** * Abstracts away the similarities between visiting the unknown type and the * all type. * @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE} * @return the restricted type * @see #caseAllType * @see #caseUnknownType */ protected abstract JSType caseTopType(JSType topType); public JSType caseAllType() { return caseTopType(getNativeType(ALL_TYPE)); } public JSType caseUnknownType() { return caseTopType(getNativeType(UNKNOWN_TYPE)); } public JSType caseUnionType

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(UnionType type) { JSType restricted = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; } public JSType caseNoType() { return getNativeType(NO_TYPE); } public JSType caseEnumElementType(EnumElementType enumElementType) { // NOTE(nicksantos): This is a white lie. Suppose we have: // /** @enum {string|number} */ var MyEnum = ...; // if (goog.isNumber(myEnumInstance)) { // /* what is myEnumInstance here? */ // } // There is no type that represents {MyEnum - string}. What we really // need is a notion of "enum subtyping", so that we could dynamically // create a subtype of MyEnum restricted by string. In any case, // this should catch the common case. JSType type = enumElementType.getPrimitiveType().visit(this); if (type != null && enumElementType.getPrimitiveType().equals(type)) { return enumElementType; } else { return type; } } } /** * A class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being true. All base cases return * {@code null}. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByTrueTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { public JSType caseNoObjectType() { return null; } public JSType caseBooleanType() { return null; } public JSType caseFunctionType(FunctionType type) { return null; } public JSType caseNullType() { return null; } public JSType caseNumberType() { return null; } public JSType caseObjectType(ObjectType type) { return null; } public JSType caseStringType() { return null; } public JSType caseVoidType() { return null; } } /** * A

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> class common to all visitors that need to restrict the type based on * some {@code typeof}-like condition being false. All base cases return * their type. It is up to the subclasses to override the appropriate ones. */ abstract class RestrictByFalseTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { @Override protected JSType caseTopType(JSType topType) { return topType; } public JSType caseNoObjectType() { return getNativeType(NO_OBJECT_TYPE); } public JSType caseBooleanType() { return getNativeType(BOOLEAN_TYPE); } public JSType caseFunctionType(FunctionType type) { return type; } public JSType caseNullType() { return getNativeType(NULL_TYPE); } public JSType caseNumberType() { return getNativeType(NUMBER_TYPE); } public JSType caseObjectType(ObjectType type) { return type; } public JSType caseStringType() { return getNativeType(STRING_TYPE); } public JSType caseVoidType() { return getNativeType(VOID_TYPE); } } /** * @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult */ private class RestrictByOneTypeOfResultVisitor extends RestrictByTypeOfResultVisitor { /** * A value known to be equal or not equal to the result of the * {@code typeOf} operation. */ private final String value; /** * {@code true} if the {@code typeOf} result is known to equal * {@code value}; {@code false} if it is known <em>not</em> to equal * {@code value}. */ private final boolean resultEqualsValue; RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) { this.value = value; this.resultEqualsValue = resultEqualsValue; } /** * Computes whether the given result of a {@code typeof} operator matches * expectations, i.e. whether a type that gives such a result should be * kept. */ private boolean matchesExpectation(String result) { return result.equals(value) == resultEqualsValue; } @Override protected JSType caseTopType(JSType topType) { if (

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>resultEqualsValue) { if (value.equals("number")) { return getNativeType(NUMBER_TYPE); } else if (value.equals("boolean")) { return getNativeType(BOOLEAN_TYPE); } else if (value.equals("string")) { return getNativeType(STRING_TYPE); } else if (value.equals("undefined")) { return getNativeType(VOID_TYPE); } else if (value.equals("function")) { return getNativeType(U2U_CONSTRUCTOR_TYPE); } } return topType; } public JSType caseNoObjectType() { return (value.equals("object") || value.equals("function")) == resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null; } public JSType caseBooleanType() { return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null; } public JSType caseFunctionType(FunctionType type) { return matchesExpectation("function") ? type : null; } public JSType caseNullType() { return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null; } public JSType caseNumberType() { return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null; } public JSType caseObjectType(ObjectType type) { if (value.equals("function")) { JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE); return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null; } return matchesExpectation("object") ? type : null; } public JSType caseStringType() { return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null; } public JSType caseVoidType() { return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null; } } /** * Returns a version of type where undefined is not present. */ final JSType getRestrictedWithoutUndefined(JSType type) { return type == null ? null : type.visit(restrictUndefinedVisitor); } /** * Returns a version of type where null is not present. */ final JSType getRestrictedWithoutNull(JSType type) { return

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> != null) { check(externsRoot, true); } check(jsRoot, false); potentialChecks.flush(); } /** Main entry point of this phase for testing code. */ public Scope processForTesting(Node externsRoot, Node jsRoot) { Preconditions.checkState(scopeCreator == null); Preconditions.checkState(topScope == null); Preconditions.checkState(jsRoot.getParent() != null); Node externsAndJsRoot = jsRoot.getParent(); scopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler)); topScope = scopeCreator.createScope(externsAndJsRoot, null); TypeInferencePass inference = new TypeInferencePass(compiler, reverseInterpreter, topScope, scopeCreator); inference.process(externsRoot, jsRoot); process(externsRoot, jsRoot); return topScope; } public void check(Node node, boolean externs) { Preconditions.checkNotNull(node); NodeTraversal t = new NodeTraversal(compiler, this, scopeCreator); inExterns = externs; t.traverseWithScope(node, topScope); if (externs) { inferJSDocInfo.process(node, null); } else { inferJSDocInfo.process(null, node); } } public boolean shouldTraverse( NodeTraversal t, Node n, Node parent) { JSDocInfo info; switch (n.getType()) { case Token.SCRIPT: case Token.VAR: // @notypecheck info = n.getJSDocInfo(); if (info != null && info.isNoTypeCheck()) { return false; } break; case Token.FUNCTION: // @notypecheck info = n.getJSDocInfo(); info = (info == null) ? parent.getJSDocInfo() : info; if (info != null && info.isNoTypeCheck()) { return false; } // normal type checking final TypeCheck outerThis = this; final Scope outerScope = t.getScope(); final FunctionType functionType = (FunctionType) n.getJSType(); final String functionPrivateName = n.getFirstChild().getString(); if (functionPrivateName != null

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> break; case Token.REF_SPECIAL: ensureTyped(t, n); break; case Token.GET_REF: ensureTyped(t, n, getJSType(n.getFirstChild())); break; case Token.NULL: ensureTyped(t, n, NULL_TYPE); break; case Token.NUMBER: if (n.getParent().getType() != Token.OBJECTLIT) { ensureTyped(t, n, NUMBER_TYPE); } else { typeable = false; } break; case Token.ARRAYLIT: ensureTyped(t, n, ARRAY_TYPE); break; case Token.STRING: if (n.getParent().getType() != Token.OBJECTLIT) { ensureTyped(t, n, STRING_TYPE); } else { typeable = false; } break; case Token.REGEXP: ensureTyped(t, n, REGEXP_TYPE); break; case Token.GETPROP: visitGetProp(t, n, parent); typeable = !(parent.getType() == Token.ASSIGN && parent.getFirstChild() == n); break; case Token.GETELEM: visitGetElem(t, n); // The type of GETELEM is always unknown, so no point counting that. // If that unknown leaks elsewhere (say by an assignment to another // variable), then it will be counted. typeable = false; break; case Token.VAR: visitVar(t, n); typeable = false; break; case Token.NEW: visitNew(t, n); typeable = true; break; case Token.CALL: visitCall(t, n); typeable = !NodeUtil.isExpressionNode(parent); break; case Token.RETURN: visitReturn(t, n); typeable = false; break; case Token.DEC: case Token.INC: left = n.getFirstChild(); validator.expectNumber( t, left, getJSType(left), "increment/decrement"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.NOT: ensureTyped(t, n, BOOLEAN_TYPE); break; case Token.VOID:

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> ensureTyped(t, n, VOID_TYPE); break; case Token.TYPEOF: ensureTyped(t, n, STRING_TYPE); break; case Token.BITNOT: childType = getJSType(n.getFirstChild()); if (!childType.matchesInt32Context()) { t.report(n, BIT_OPERATION, NodeUtil.opToStr(n.getType()), childType.toString()); } ensureTyped(t, n, NUMBER_TYPE); break; case Token.POS: case Token.NEG: left = n.getFirstChild(); validator.expectNumber(t, left, getJSType(left), "sign operator"); ensureTyped(t, n, NUMBER_TYPE); break; case Token.EQ: case Token.NE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); TernaryValue result = leftTypeRestricted.testForEquality(rightTypeRestricted); if (result != TernaryValue.UNKNOWN) { if (n.getType() == Token.NE) { result = result.not(); } t.report(n, DETERMINISTIC_TEST, leftType.toString(), rightType.toString(), result.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.SHEQ: case Token.SHNE: { leftType = getJSType(n.getFirstChild()); rightType = getJSType(n.getLastChild()); JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined(); JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined(); if (!leftTypeRestricted.canTestForShallowEqualityWith( rightTypeRestricted)) { t.report(n, DETERMINISTIC_TEST_NO_RESULT, leftType.toString(), rightType.toString()); } ensureTyped(t, n, BOOLEAN_TYPE); break; } case Token.LT: case Token.LE: case Token.GT: case Token.GE: left

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Resolved()) { return namedType.getReferenceName(); } } else if (type.isUnionType()) { for (JSType alt : ((UnionType) type).getAlternates()) { if (alt.isUnknownType()) { String unresolvedReference = getUnresolvedReference(alt); if (unresolvedReference != null) { return unresolvedReference; } } } } return null; } /** * Visits an assignment <code>lvalue = rvalue</code>. If the * <code>lvalue</code> is a prototype modification, we change the schema * of the object type it is referring to. * @param t the traversal * @param assign the assign node * (<code>assign.getType() == Token.ASSIGN</code> is an implicit invariant) */ private void visitAssign(NodeTraversal t, Node assign) { JSDocInfo info = assign.getJSDocInfo(); Node lvalue = assign.getFirstChild(); Node rvalue = assign.getLastChild(); if (lvalue.getType() == Token.GETPROP) { Node object = lvalue.getFirstChild(); JSType objectJsType = getJSType(object); String property = lvalue.getLastChild().getString(); // the first name in this getprop refers to an interface // we perform checks in addition to the ones below if (object.getType() == Token.GETPROP) { JSType jsType = getJSType(object.getFirstChild()); if (jsType.isInterface() && object.getLastChild().getString().equals("prototype")) { visitInterfaceGetprop(t, assign, object, property, lvalue, rvalue); } } // /** @type ... */object.name = ...; if (info != null && info.hasType()) { visitAnnotatedAssignGetprop(t, assign, info.getType().evaluate(t.getScope()), object, property, rvalue); return; } // /** @enum ... */object.name = ...; if (info != null && info.hasEnumParameterType()) { checkEnumInitializer( t, rvalue, info.getEnumParameterType().evaluate(t.getScope())); return; } // object.prototype = ...

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>; if (property.equals("prototype")) { if (objectJsType instanceof FunctionType) { FunctionType functionType = (FunctionType) objectJsType; if (functionType.isConstructor()) { JSType rvalueType = rvalue.getJSType(); validator.expectObject(t, rvalue, rvalueType, OVERRIDING_PROTOTYPE_WITH_NON_OBJECT); } } else { // TODO(user): might want to flag that } return; } // object.prototype.property = ...; if (object.getType() == Token.GETPROP) { Node object2 = object.getFirstChild(); String property2 = NodeUtil.getStringValue(object.getLastChild()); if ("prototype".equals(property2)) { JSType jsType = object2.getJSType(); if (jsType instanceof FunctionType) { FunctionType functionType = (FunctionType) jsType; if (functionType.isConstructor() || functionType.isInterface()) { checkDeclaredPropertyInheritance( t, assign, functionType, property, info, getJSType(rvalue)); } } else { // TODO(user): might want to flag that } return; } } // object.property = ...; ObjectType type = ObjectType.cast( objectJsType.restrictByNotNullOrUndefined()); if (type != null) { if (type.hasProperty(property) && !type.isPropertyTypeInferred(property) && !propertyIsImplicitCast(type, property)) { validator.expectCanAssignToPropertyOf( t, assign, getJSType(rvalue), type.getPropertyType(property), object, property); } return; } } else if (lvalue.getType() == Token.NAME) { // variable with inferred type case JSType rvalueType = getJSType(assign.getLastChild()); Var var = t.getScope().getVar(lvalue.getString()); if (var != null) { if (var.isTypeInferred()) { return; } } } // fall through case JSType leftType = getJSType(lvalue); Node rightChild = assign.getLastChild(); JSType rightType = getJSType(rightChild);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>, propertyName, ctorType.getInstanceType().toString())); } } /** * Visits an ASSIGN node for cases such as * <pre> * interface.property2.property = ...; * </pre> */ private void visitInterfaceGetprop(NodeTraversal t, Node assign, Node object, String property, Node lvalue, Node rvalue) { JSType rvalueType = getJSType(rvalue); String abstractMethodName = compiler.getCodingConvention().getAbstractMethodName(); if (!rvalueType.isOrdinaryFunction() && !(rvalue.isQualifiedName() && rvalue.getQualifiedName().equals(abstractMethodName))) { compiler.report(JSError.make(t, object, INTERFACE_FUNCTION_MEMBERS_ONLY, abstractMethodName)); } if (assign.getLastChild().getType() == Token.FUNCTION && !NodeUtil.isEmptyBlock(assign.getLastChild().getLastChild())) { compiler.report(JSError.make(t, object, INTERFACE_FUNCTION_NOT_EMPTY, abstractMethodName)); } } /** * Visits an ASSIGN node for cases such as * <pre> * object.property = ...; * </pre> * that have an {@code @type} annotation. */ private void visitAnnotatedAssignGetprop(NodeTraversal t, Node assign, JSType type, Node object, String property, Node rvalue) { // verifying that the rvalue has the correct type validator.expectCanAssignToPropertyOf(t, assign, getJSType(rvalue), type, object, property); } /** * Visits a NAME node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. * @param parent The parent of the node n. * @return whether the node is typeable or not */ boolean visitName(NodeTraversal t, Node n, Node parent) { // At this stage, we need to determine whether this is a leaf // node in an expression (which therefore needs to have a type // assigned for it) versus some other decorative node that we // can safely ignore.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> return; } checkPropertyAccess(childType, property.getString(), t, n); ensureTyped(t, n); } /** * Make sure that the access of this property is ok. */ private void checkPropertyAccess(JSType childType, String propName, NodeTraversal t, Node n) { ObjectType objectType = childType.dereference(); if (objectType != null) { JSType propType = getJSType(n); if ((!objectType.hasProperty(propName) || objectType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) && propType.equals(typeRegistry.getNativeType(UNKNOWN_TYPE))) { if (objectType instanceof EnumType) { t.report(n, INEXISTENT_ENUM_ELEMENT, propName); } else if (!objectType.isEmptyType() && reportMissingProperties && !isPropertyTest(n)) { if (!typeRegistry.canPropertyBeDefined(objectType, propName)) { t.report(n, INEXISTENT_PROPERTY, propName, validator.getReadableJSTypeName(n.getFirstChild(), true)); } } } } else { // TODO(nicksantos): might want to flag the access on a non object when // it's impossible to get a property from this type. } } /** * Determines whether this node is testing for the existence of a property. * If true, we will not emit warnings about a missing property. * * @param getProp The GETPROP being tested. */ private boolean isPropertyTest(Node getProp) { Node parent = getProp.getParent(); switch (parent.getType()) { case Token.CALL: return parent.getFirstChild() != getProp && compiler.getCodingConvention().isPropertyTestFunction(parent); case Token.IF: case Token.WHILE: case Token.DO: case Token.FOR: return NodeUtil.getConditionExpression(parent) == getProp; case Token.INSTANCEOF: case Token.TYPEOF: return true; case Token.AND: case Token.HOOK: return parent.getFirstChild() == getProp; } return false; } /** * Visits a GET

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> != null) { FunctionType interfaceConstructor = baseInterfaceObj.getConstructor(); if (interfaceConstructor != null && !interfaceConstructor.isInterface()) { badImplementedType = true; } } else { badImplementedType = true; } if (badImplementedType) { t.report(n, BAD_IMPLEMENTED_TYPE, functionPrivateName); } } if (functionType.isConstructor()) { validator.expectAllInterfacePropertiesImplemented(functionType); } } } /** * Visits a CALL node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitCall(NodeTraversal t, Node n) { Node child = n.getFirstChild(); JSType childType = getJSType(child).restrictByNotNullOrUndefined(); if (!childType.canBeCalled()) { t.report(n, NOT_CALLABLE, childType.toString()); ensureTyped(t, n); return; } // A couple of types can be called as if they were functions. // If it is a function type, then validate parameters. if (childType instanceof FunctionType) { FunctionType functionType = (FunctionType) childType; // Non-native constructors should never be called directly. if (functionType.isConstructor() && !functionType.isNativeObjectType()) { t.report(n, CONSTRUCTOR_NOT_CALLABLE, childType.toString()); } visitParameterList(t, n, functionType); ensureTyped(t, n, functionType.getReturnType()); } else { ensureTyped(t, n); } // TODO: Add something to check for calls of RegExp objects, which is not // supported by IE. Either say something about the return type or warn // about the non-portability of the call or both. } /** * Visits the parameters of a CALL or a NEW node. */ private void visitParameterList(NodeTraversal t, Node call, FunctionType functionType) { Iterator<Node> arguments = call.children().iterator(); arguments.next(); // skip the function name

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Iterator<Node> parameters = functionType.getParameters().iterator(); int ordinal = 0; while (arguments.hasNext() && parameters.hasNext()) { Node parameter = parameters.next(); Node argument = arguments.next(); ordinal++; validator.expectArgumentMatchesParameter(t, argument, getJSType(argument), getJSType(parameter), call, ordinal); } int numArgs = call.getChildCount() - 1; int minArgs = functionType.getMinArguments(); int maxArgs = functionType.getMaxArguments(); if (minArgs > numArgs || maxArgs < numArgs) { t.getCompiler().report( JSError.make(t, call, WRONG_ARGUMENT_COUNT, validator.getReadableJSTypeName(call.getFirstChild(), false), String.valueOf(numArgs), String.valueOf(minArgs), maxArgs != Integer.MAX_VALUE ? " and no more than " + maxArgs + " argument(s)" : "")); } } /** * Visits a RETURN node. * * @param t The node traversal object that supplies context, such as the * scope chain to use in name lookups as well as error reporting. * @param n The node being visited. */ private void visitReturn(NodeTraversal t, Node n) { Node function = t.getEnclosingFunction(); // This is a misplaced return, but the real JS will fail to compile, // so let it go. if (function == null) { return; } JSType jsType = getJSType(function); if (jsType instanceof FunctionType) { FunctionType functionType = (FunctionType) jsType; JSType returnType = functionType.getReturnType(); // if no return type is specified, undefined must be returned // (it's a void function) if (returnType == null) { returnType = getNativeType(VOID_TYPE); } // fetching the returned value's type Node valueNode = n.getFirstChild(); JSType actualReturnType; if (valueNode == null) { actualReturnType = getNativeType(VOID_TYPE); valueNode = n; } else { actualReturnType = getJSType(valueNode); } // verifying validator.expectCanAssignTo

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(t, valueNode, actualReturnType, returnType, "inconsistent return type"); } } /** * This function unifies the type checking involved in the core binary * operators and the corresponding assignment operators. The representation * used internally is such that common code can handle both kinds of * operators easily. * * @param op The operator. * @param t The traversal object, needed to report errors. * @param n The node being checked. */ private void visitBinaryOperator(int op, NodeTraversal t, Node n) { Node left = n.getFirstChild(); JSType leftType = getJSType(left); Node right = n.getLastChild(); JSType rightType = getJSType(right); switch (op) { case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.LSH: case Token.RSH: case Token.ASSIGN_URSH: case Token.URSH: if (!leftType.matchesInt32Context()) { t.report(left, BIT_OPERATION, NodeUtil.opToStr(n.getType()), leftType.toString()); } if (!rightType.matchesUint32Context()) { t.report(right, BIT_OPERATION, NodeUtil.opToStr(n.getType()), rightType.toString()); } break; case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN_MUL: case Token.ASSIGN_SUB: case Token.DIV: case Token.MOD: case Token.MUL: case Token.SUB: validator.expectNumber(t, left, leftType, "left operand"); validator.expectNumber(t, right, rightType, "right operand"); break; case Token.ASSIGN_BITAND: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITOR: case Token.BITAND: case Token.BITXOR: case Token.BITOR: validator.expectBitwiseable(t, left, leftType, "bad left operand to bitwise operator"); validator.expectBitwiseable(t, right, rightType, "bad right operand to bitwise operator"); break; case Token.ASSIGN_ADD

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; /** * A factory for creating JSCompiler passes based on the Options * injected. Contains all meta-data about compiler passes (like * whether it can be run multiple times, a human-readable name for * logging, etc.). * * @author nicksantos@google.com (Nick Santos) */ public abstract class PassFactory { private final String name; private final boolean isOneTimePass; private boolean isCreated = false; /** * @param name The name of the pass that this factory creates. * @param isOneTimePass If true, the pass produced by this factory can * only be run once. */ protected PassFactory(String name, boolean isOneTimePass) { this.name = name; this.isOneTimePass = isOneTimePass; } /** * @return The name of this pass. */ String getName() { return name; } /** * @return Whether the pass produced by this factory can only be run once. */ boolean isOneTimePass() { return isOneTimePass; } /** * Make a new pass factory that only creates one-time passes. */ PassFactory makeOneTimePass() { if (isOneTimePass()) { return this; } final PassFactory self = this; return new PassFactory(name, true /* one time pass */) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return self.createInternal(compiler); }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.javascript.jscomp.NodeTraversal.ScopedCallback; import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Provides common data structures for program analysis. * * Clients of the symbol table are strictly responsible for keeping * the data structures up to date. The testing infrastructure is * responsible for verifying that they do this. * * If a pass does not want to keep its data structures up to date, * then it should not use the symbol table--it should directly invoke * the factory for the data structure it wants. * * @author nicksantos@google.com (Nick Santos) */ class SymbolTable implements ScopeCreator, CodeChangeHandler { static final DiagnosticType MISSING_VARIABLE = DiagnosticType.error( "JSC_MISSING_VARIABLE", "Missing variable name: {0}"); static final DiagnosticType MOVED_VARIABLE = DiagnosticType.error( "JSC_MOVED_VARIABLE", "Moved variable name: {0}"); static final DiagnosticType VARIABLE_COUNT_MISMATCH = DiagnosticType.error( "JSC_VARIABLE_COUNT_MISMATCH", "Variable count does not match."

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> data structures cached by this table. */ private static class MemoizedData { private Map<Node, Scope> scopes = Maps.newHashMap(); } //---------------------------------------------------------------------------- // Verification of consistency. Only for tests. /** * Check that this symbol table has been kept up to date. Compiler warnings * will be emitted if anything is wrong. * @param expectedRoot The root of the expected AST. * @param actualRoot The root of the actual AST used with this symbol table. */ void verify(Node expectedRoot, Node actualRoot) { VerifyingCallback callback = new VerifyingCallback( expectedRoot, actualRoot); callback.verify(); } /** * A callback that traverses an AST root and builds all the * secondary data structures for it. */ private class VerifyingCallback implements ScopedCallback { private final List<Scope> expectedScopes = Lists.newArrayList(); private final List<Scope> actualScopes = Lists.newArrayList(); private boolean collectingExpected = true; private final Node actualRoot; private final Node expectedRoot; private VerifyingCallback(Node expectedRoot, Node actualRoot) { this.actualRoot = actualRoot; this.expectedRoot = expectedRoot; } @Override public boolean shouldTraverse( NodeTraversal nodeTraversal, Node n, Node parent) { return true; } @Override public void visit(NodeTraversal t, Node n, Node parent) {} @Override public void enterScope(NodeTraversal t) {} @Override public void exitScope(NodeTraversal t) { if (collectingExpected) { expectedScopes.add(t.getScope()); } else { actualScopes.add(t.getScope()); } } private void verify() { if (cache == null) { // The symbol table was never used, so no need to check anything. return; } if (!cache.scopes.isEmpty()) { verifyScopes(); } } private void verifyScopes() { collectingExpected = true; NodeTraversal.traverse(compiler, expectedRoot, this); collectingExpected = false; (new NodeTraversal(compiler, this, SymbolTable.this)) .traverse(actualRoot); // This must be true unless something went horribly, horribly wrong.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Preconditions.checkState(expectedScopes.size() == actualScopes.size()); for (int i = 0; i < expectedScopes.size(); i++) { Scope expectedScope = expectedScopes.get(i); Scope actualScope = actualScopes.get(i); if (!checkNodesMatch(expectedScope.getRootNode(), actualScope.getRootNode())) { compiler.report( JSError.make( SCOPE_MISMATCH, expectedScope.getRootNode().toStringTree(), actualScope.getRootNode().toStringTree())); continue; } if (expectedScope.getVarCount() != actualScope.getVarCount()) { compiler.report( JSError.make( VARIABLE_COUNT_MISMATCH, Integer.toString(expectedScope.getVarCount()), Integer.toString(actualScope.getVarCount()))); } else { Iterator<Var> it = expectedScope.getVars(); while (it.hasNext()) { Var var = it.next(); Scope.Var actualVar = actualScope.getVar(var.getName()); if (actualVar == null || expectedScope.getVar(var.getName()) != var) { compiler.report( JSError.make(MISSING_VARIABLE, var.getName())); } else if ( !checkNodesMatch( var.getNameNode(), actualVar.getNameNode()) || !isNodeAttached(actualVar.getNameNode())) { compiler.report( JSError.make(MOVED_VARIABLE, var.getName())); } } } } } /** * Check that the two nodes have the same relative position in the tree. */ private boolean checkNodesMatch(Node nodeA, Node nodeB) { Node currentA = nodeA; Node currentB = nodeB; while (currentA != null && currentB != null) { if (currentA.getType() != currentB.getType() || !currentA.isEquivalentTo(currentB)) { return false; } currentA = currentA.getParent(); currentB = currentB.getParent(); } return currentA == null && currentB == null; } private boolean isNodeAttached(Node node) { // Make sure the cached var is still attached. for (Node current = node; current != null; current

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> = current.getParent()) { if (current.getType() == Token.SCRIPT) { return true; } } return false; } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.mozilla.rhino.ast.SwitchStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.ThrowStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.TryStatement; import com.google.javascript.jscomp.mozilla.rhino.ast.UnaryExpression; import com.google.javascript.jscomp.mozilla.rhino.ast.VariableDeclaration; import com.google.javascript.jscomp.mozilla.rhino.ast.VariableInitializer; import com.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop; import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.ScriptOrFnNode; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.JSTypeRegistry; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; /** * IRFactory transforms the new AST to the old AST. * * */ public class IRFactory { private final String sourceString; private final String sourceName; private final Config config; private final JSTypeRegistry registry; private final ErrorReporter errorReporter; private final TransformDispatcher transformDispatcher; // non-static for thread safety private final Set<String> ALLOWED_DIRECTIVES = Sets.newHashSet("use strict"); // Nodes with JSDoc comments, indexed by the text of the JSDoc comment. // // It's likely that two or more nodes in the same file may have the same // jsdoc comment. In general, that's ok. // // There's one edge case where this might cause problems. If two JSDoc // comments have the same text, and the first JSDoc comment is not attached // to a node, then the second node will get the first JSDoc comment // instead of the second. When this happens, it probably won't cause any // problems. The two JSDoc comments will be exactly the same,

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * @param comment The JsDoc comment to parse. * @param lineno The line number of the node this comment is attached to. * @param fileLevelJsDocBuilder The builder for file-level JSDocInfo. * @param fileOverviewInfo The current @fileoverview JSDocInfo, so that the * parser may warn if another @fileoverview is found. May be null. * @return A JSDocInfoParser. Will contain either fileoverview jsdoc, or * normal jsdoc, or no jsdoc (if the method parses to the wrong level). */ private JsDocInfoParser createJsDocInfoParser( String comment, int lineno, int position, Node.FileLevelJsDocBuilder fileLevelJsDocBuilder, JSDocInfo fileOverviewInfo) { // The JsDocInfoParser expects the comment without the initial '/**'. int numOpeningChars = 3; JsDocInfoParser jsdocParser = new JsDocInfoParser( new JsDocTokenStream(comment.substring(numOpeningChars), lineno, position2charno(position) + numOpeningChars), sourceName, config, errorReporter); jsdocParser.setFileLevelJsDocBuilder(fileLevelJsDocBuilder); jsdocParser.setFileOverviewJSDocInfo(fileOverviewInfo); jsdocParser.parse(); return jsdocParser; } /** Attach JSDocInfo to a node, if we can find one. */ private void attachJsDoc(Comment comment, JSDocInfo info) { Collection<NodeWithJsDoc> candidates = nodesWithJsDoc.get(comment.getValue()); if (candidates.isEmpty()) { return; } Iterator<NodeWithJsDoc> candidateIter = candidates.iterator(); Node node = candidateIter.next().node; candidateIter.remove(); node.setJSDocInfo(info); if (info.hasEnumParameterType()) { if (node.getType() == Token.NAME) { registry.identifyEnumName(node.getString()); } else if (node.getType() == Token.VAR && node.getChildCount() == 1) { registry.identifyEnumName( node.getFirstChild().getString()); } else if (node.getType() == Token.ASSIGN

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> node.addChildToBack(c); } if (skipCount > 0) { int[] skipIndexes = new int[skipCount]; int i = 0; int j = 0; for (Node child : node.children()) { if (child.getType() == Token.EMPTY) { node.removeChild(child); skipIndexes[j] = i; j++; } i++; } node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes); } return node; } @Override Node processAssignment(Assignment assignmentNode) { return processInfixExpression(assignmentNode); } @Override Node processAstRoot(AstRoot rootNode) { Node node = new ScriptOrFnNode(Token.SCRIPT); for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) { node.addChildToBack(transform((AstNode)child)); } parseDirectives(node); return node; } /** * Parse the directives, encode them in the AST, and remove their nodes. * * For information on ES5 directives, see section 14.1 of * Ecma-262, Edition 5. * * It would be nice if Rhino would eventually take care of this for * us, but right now their directive-processing is a one-off. */ private void parseDirectives(Node node) { // Remove all the directives, and encode them in the AST. Set<String> directives = null; while (isDirective(node.getFirstChild())) { String directive = node.removeFirstChild().getFirstChild().getString(); if (directives == null) { directives = Sets.newHashSet(directive); } else { directives.add(directive); } } if (directives != null) { node.setDirectives(directives); } } private boolean isDirective(Node n) { if (n == null) return false; int nType = n.getType(); return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) && n.getFirstChild().getType() == Token.STRING && ALLOWED_DIRECTIVES.contains(n.getFirstChild

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> // Position in new ASTNode is to start of expression, but old-fashioned // line numbers from Node reference the operator token. Add the offset // to the operator to get the correct character number. n.setCharno(position2charno(exprNode.getAbsolutePosition() + exprNode.getOperatorPosition())); return n; } @Override Node processKeywordLiteral(KeywordLiteral literalNode) { return new Node(transformTokenType(literalNode.getType())); } @Override Node processLabel(Label labelNode) { return Node.newString(Token.NAME, labelNode.getName()); } @Override Node processLabeledStatement(LabeledStatement statementNode) { Node node = new Node(Token.LABEL); Node prev = null; Node cur = node; for (Label label : statementNode.getLabels()) { if (prev != null) { prev.addChildToBack(cur); } cur.addChildToBack(transform(label)); prev = cur; cur = new Node(Token.LABEL); } prev.addChildToBack(transform(statementNode.getStatement())); return node; } @Override Node processName(Name nameNode) { return Node.newString(Token.NAME, nameNode.getIdentifier()); } @Override Node processNewExpression(NewExpression exprNode) { return processFunctionCall(exprNode); } @Override Node processNumberLiteral(NumberLiteral literalNode) { Node newNode = Node.newNumber(literalNode.getNumber()); return newNode; } @Override Node processObjectLiteral(ObjectLiteral literalNode) { if (literalNode.isDestructuring()) { reportDestructuringAssign(literalNode); } Node node = new Node(Token.OBJECTLIT); for (ObjectProperty el : literalNode.getElements()) { node.addChildToBack(transformAsString(el.getLeft())); node.addChildToBack(transform(el.getRight())); } return node; } @Override Node processObjectProperty(ObjectProperty propertyNode) { return processInfixExpression(propertyNode); } @Override Node processParenthesizedExpression(ParenthesizedExpression exprNode) { Node node = transform(exprNode.getExpression()); node

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.append(':'); b.append(error.lineNumber); } b.append(": "); } b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR)); b.append(" - "); b.append(error.description); b.append('\n'); if (sourceExcerpt != null) { b.append(sourceExcerpt); b.append('\n'); int charno = error.getCharno(); // padding equal to the excerpt and arrow at the end if (excerpt.equals(LINE) && 0 <= charno && charno < sourceExcerpt.length()) { for (int i = 0; i < charno; i++) { char c = sourceExcerpt.charAt(i); if (Character.isWhitespace(c)) { b.append(c); } else { b.append(' '); } } b.append("^\n"); } } return b.toString(); } /** * Formats a region by appending line numbers in front, e.g. * <pre> 9| if (foo) { * 10| alert('bar'); * 11| }</pre> * and return line excerpt without any modification. */ static class LineNumberingFormatter implements ExcerptFormatter { public String formatLine(String line, int lineNumber) { return line; } public String formatRegion(Region region) { if (region == null) { return null; } String code = region.getSourceExcerpt(); if (code.length() == 0) { return null; } // max length of the number display int numberLength = Integer.toString(region.getEndingLineNumber()) .length(); // formatting StringBuilder builder = new StringBuilder(code.length() * 2); int start = 0; int end = code.indexOf('\n', start); int lineNumber = region.getBeginningLineNumber(); while (start >= 0) { // line extraction String line; if (end < 0) { line = code.substring(start); if (line.length() == 0) { return builder.substring(0, builder.length() -

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> /** * Gets the number of properties of this object. */ @Override public int getPropertiesCount() { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype == null) { return this.properties.size(); } int localCount = 0; for (String property : properties.keySet()) { if (!implicitPrototype.hasProperty(property)) { localCount++; } } return implicitPrototype.getPropertiesCount() + localCount; } @Override public boolean hasProperty(String propertyName) { if (properties.get(propertyName) != null) { return true; } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.hasProperty(propertyName); } return false; } @Override public boolean hasOwnProperty(String propertyName) { return properties.get(propertyName) != null; } @Override public Set<String> getOwnPropertyNames() { return properties.keySet(); } @Override public boolean isPropertyTypeDeclared(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeDeclared(property); } // property does not exist return false; } return !p.inferred; } @Override protected void collectPropertyNames(Set<String> props) { for (String prop : properties.keySet()) { props.add(prop); } ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { implicitPrototype.collectPropertyNames(props); } } @Override public boolean isPropertyTypeInferred(String property) { Property p = properties.get(property); if (p == null) { ObjectType implicitPrototype = getImplicitPrototype(); if (implicitPrototype != null) { return implicitPrototype.isPropertyTypeInferred(property); } // property does not exist return false; } return p.inferred; } @Override public JSType getPropertyType(String propertyName) { Property p = properties.get(propertyName); if (p != null) { return p.type; } ObjectType implicitPrototype = getImplicit

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>link CompilerOptions}. */ private MessageFormatter createMessageFormatter() { boolean colorize = options_.shouldColorizeErrorOutput(); return options_.errorFormat.toFormatter(this, colorize); } /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSSourceFile[] inputs, CompilerOptions options) { externs_ = makeCompilerInput(externs, true); modules_ = null; moduleGraph_ = null; inputs_ = makeCompilerInput(inputs, false); options_ = options; initBasedOnOptions(); initInputsByNameMap(); } static final DiagnosticType MODULE_DEPENDENCY_ERROR = DiagnosticType.error("JSC_MODULE_DEPENDENCY_ERROR", "Bad dependency: {0} -> {1}. " + "Modules must be listed in dependency order."); /** * Initializes the instance state needed for a compile job. */ public void init(JSSourceFile[] externs, JSModule[] modules, CompilerOptions options) { checkFirstModule(modules); externs_ = makeCompilerInput(externs, true); modules_ = modules; // Generate the module graph, and report any errors in the module // specification as errors. try { moduleGraph_ = new JSModuleGraph(modules); } catch (JSModuleGraph.ModuleDependenceException e) { // problems with the module format. Report as an error. The // message gives all details. report(JSError.make(MODULE_DEPENDENCY_ERROR, e.getModule().getName(), e.getDependentModule().getName())); return; } inputs_ = getAllInputsFromModules(); options_ = options; initBasedOnOptions(); initInputsByNameMap(); } /** * Do any initialization that is dependent on the compiler options. */ private void initBasedOnOptions() { // Create the source map if necessary. if (options_.sourceMapOutputPath != null) { sourceMap_ = new SourceMap(); } } private CompilerInput[] makeCompilerInput( JSSourceFile[] files, boolean isExtern) { CompilerInput [] inputs = new CompilerInput[files.length]; for (int i = 0;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> i < files.length; ++i) { inputs[i] = new CompilerInput(files[i], isExtern); } return inputs; } private static final DiagnosticType EMPTY_MODULE_LIST_ERROR = DiagnosticType.error("JSC_EMPTY_MODULE_LIST_ERROR", "At least one module must be provided"); private static final DiagnosticType EMPTY_ROOT_MODULE_ERROR = DiagnosticType.error("JSC_EMPTY_ROOT_MODULE_ERROR", "Root module '{0}' must contain at least one source code input"); /** * Verifies that at least one module has been provided and that the first one * has at least one source code input. */ private void checkFirstModule(JSModule[] modules) { if (modules.length == 0) { report(JSError.make(EMPTY_MODULE_LIST_ERROR)); } else if (modules[0].getInputs().isEmpty()) { report(JSError.make(EMPTY_ROOT_MODULE_ERROR, modules[0].getName())); } } static final DiagnosticType DUPLICATE_INPUT_IN_MODULES = DiagnosticType.error("JSC_DUPLICATE_INPUT_IN_MODULES_ERROR", "Two modules cannot contain the same input, but module {0} and {1} " + "both include \"{2}\""); /** * Rebuilds the internal list of inputs by iterating over all modules. * This is necessary if inputs have been added to or removed from a module * after the {@link #init(JSSourceFile[], JSModule[], CompilerOptions)} call. */ public void rebuildInputsFromModules() { inputs_ = getAllInputsFromModules(); initInputsByNameMap(); } /** * Builds a single list of all module inputs. Verifies that it contains no * duplicates. */ private CompilerInput[] getAllInputsFromModules() { List<CompilerInput> inputs = new ArrayList<CompilerInput>(); Map<String, JSModule> inputMap = new HashMap<String, JSModule>(); for (JSModule module : modules_) { for (CompilerInput input : module.getInputs()) { String inputName = input.getName(); JSModule firstModule = inputMap.get(inputName); if (firstModule == null) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> inputs.add(input); inputMap.put(inputName, module); } else { report(JSError.make(DUPLICATE_INPUT_IN_MODULES, firstModule.getName(), module.getName(), inputName)); } } } if (hasErrors()) { // There's no reason to bother parsing the code. return new CompilerInput[0]; } return inputs.toArray(new CompilerInput[inputs.size()]); } static final DiagnosticType DUPLICATE_INPUT = DiagnosticType.error("JSC_DUPLICATE_INPUT", "Duplicate input: {0}"); static final DiagnosticType DUPLICATE_EXTERN_INPUT = DiagnosticType.error("JSC_DUPLICATE_EXTERN_INPUT", "Duplicate extern input: {0}"); /** * Creates a map to make looking up an input by name fast. Also checks for * duplicate inputs. */ void initInputsByNameMap() { inputsByName_ = new HashMap<String, CompilerInput>(); for (CompilerInput input : externs_) { String name = input.getName(); if (!inputsByName_.containsKey(name)) { inputsByName_.put(name, input); } else { report(JSError.make(DUPLICATE_EXTERN_INPUT, name)); } } for (CompilerInput input : inputs_) { String name = input.getName(); if (!inputsByName_.containsKey(name)) { inputsByName_.put(name, input); } else { report(JSError.make(DUPLICATE_INPUT, name)); } } } public Result compile( JSSourceFile extern, JSSourceFile input, CompilerOptions options) { return compile(extern, new JSSourceFile[] { input }, options); } public Result compile( JSSourceFile extern, JSSourceFile[] input, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, input, options); } public Result compile( JSSourceFile extern, JSModule[] modules, CompilerOptions options) { return compile(new JSSourceFile[] { extern }, modules, options); } /** * Compiles a list of inputs. */ public Result compile(JSSourceFile[] externs, JSSourceFile

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>ternExportsPass(this); process(pass); externExports_ = pass.getGeneratedExterns(); endPass(); } void process(CompilerPass p) { p.process(externsRoot, jsRoot); } private final PassFactory sanityCheck = new PassFactory("sanityCheck", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new SanityCheck(compiler); } }; private void maybeSanityCheck() { if (options_.devMode == DevMode.EVERY_PASS) { runSanityCheck(); } } private void runSanityCheck() { sanityCheck.create(this).process(externsRoot, jsRoot); } /** * Removes try/catch/finally statements for easier debugging. */ void removeTryCatchFinally() { logger_.info("Remove try/catch/finally"); startPass("removeTryCatchFinally"); RemoveTryCatch r = new RemoveTryCatch(this); process(r); endPass(); } /** * Strips code for smaller compiled code. This is useful for removing debug * statements to prevent leaking them publicly. */ void stripCode(Set<String> stripTypes, Set<String> stripNameSuffixes, Set<String> stripTypePrefixes, Set<String> stripNamePrefixes) { logger_.info("Strip code"); startPass("stripCode"); StripCode r = new StripCode(this, stripTypes, stripNameSuffixes, stripTypePrefixes, stripNamePrefixes); process(r); endPass(); } /** * Runs custom passes that are designated to run at a particular time. */ private void runCustomPasses(CustomPassExecutionTime executionTime) { if (options_.customPasses != null) { Tracer t = newTracer("runCustomPasses"); try { for (CompilerPass p : options_.customPasses.get(executionTime)) { process(p); } } finally { stopTracer(t, "runCustomPasses"); } } } private Tracer currentTracer = null; private String currentPassName = null; /** * Marks the beginning of a pass. */ void startPass(String pass

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>SourceFile().getName(); Preconditions.checkState( getInput(sourceName) == null, "Duplicate input of name " + sourceName); inputsByName_.put(sourceName, new CompilerInput(ast)); } @Override JSModuleGraph getModuleGraph() { return moduleGraph_; } @Override public JSTypeRegistry getTypeRegistry() { if (typeRegistry == null) { typeRegistry = new JSTypeRegistry(oldErrorReporter); } return typeRegistry; } @Override ScopeCreator getScopeCreator() { return getPassConfig().getScopeCreator(); } @Override public Scope getTopScope() { return getPassConfig().getTopScope(); } @Override public ReverseAbstractInterpreter getReverseAbstractInterpreter() { if (abstractInterpreter == null) { ChainableReverseAbstractInterpreter interpreter = new SemanticReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()); if (options_.closurePass) { interpreter = new ClosureReverseAbstractInterpreter( getCodingConvention(), getTypeRegistry()) .append(interpreter).getFirst(); } abstractInterpreter = interpreter; } return abstractInterpreter; } @Override TypeValidator getTypeValidator() { return typeValidator; } //------------------------------------------------------------------------ // Parsing //------------------------------------------------------------------------ /** * Parses the externs and main inputs. * * @return A synthetic root node whose two children are the externs root * and the main root */ Node parseInputs() { boolean devMode = options_.devMode != DevMode.OFF; // If old roots exist (we are parsing a second time), detach each of the // individual file parse trees. if (externsRoot != null) { externsRoot.detachChildren(); } if (jsRoot != null) { jsRoot.detachChildren(); } // Parse main js sources. jsRoot = new Node(Token.BLOCK); jsRoot.setIsSyntheticBlock(true); if (options_.tracer.isOn()) { tracker = new PerformanceTracker(jsRoot, options_.tracer == TracerMode.ALL); addChangeHandler(tracker.getCodeChangeHandler()); } Tracer tracer = newTracer("parseInputs"); try { // Parse externs sources. externsRoot = new Node(Token.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>BLOCK); externsRoot.setIsSyntheticBlock(true); for (CompilerInput input : externs_) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } externsRoot.addChildToBack(n); } for (CompilerInput input : inputs_) { Node n = input.getAstRoot(this); if (hasErrors()) { return null; } // Inputs can have a null AST during initial parse. if (n == null) { continue; } if (devMode) { runSanityCheck(); if (hasErrors()) { return null; } } if (options_.sourceMapOutputPath != null || options_.nameReferenceReportPath != null) { // Annotate the nodes in the tree with information from the // input file. This information is used to construct the SourceMap. SourceInformationAnnotator sia = new SourceInformationAnnotator(input.getName()); NodeTraversal.traverse(this, n, sia); } jsRoot.addChildToBack(n); } externAndJsRoot = new Node(Token.BLOCK, externsRoot, jsRoot); externAndJsRoot.setIsSyntheticBlock(true); return externAndJsRoot; } finally { stopTracer(tracer, "parseInputs"); } } public Node parse(JSSourceFile file) { addToDebugLog("Parsing: " + file.getName()); return new JsAst(file).getAstRoot(this); } @Override Node parseSyntheticCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [synthetic] ", js)); inputsByName_.put(input.getName(), input); return input.getAstRoot(this); } @Override Node parseSyntheticCode(String fileName, String js) { return parse(JSSourceFile.fromCode(fileName, js)); } Node parseTestCode(String js) { CompilerInput input = new CompilerInput( JSSourceFile.fromCode(" [testcode] ", js)); if (inputsByName_ == null) { inputsByName_ = Maps.newHashMap(); } inputsByName_.put(input

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.getName(), input); return input.getAstRoot(this); } @Override ErrorReporter getDefaultErrorReporter() { return defaultErrorReporter; } //------------------------------------------------------------------------ // Convert back to source code //------------------------------------------------------------------------ /** * Converts the main parse tree back to js code. */ public String toSource() { return runInCompilerThread(new Callable<String>() { public String call() throws Exception { Tracer tracer = newTracer("toSource"); try { CodeBuilder cb = new CodeBuilder(); if (jsRoot != null) { int i = 0; for (Node scriptNode = jsRoot.getFirstChild(); scriptNode != null; scriptNode = scriptNode.getNext()) { toSource(cb, i++, scriptNode); } } return cb.toString(); } finally { stopTracer(tracer, "toSource"); } } }); } /** * Converts the parse tree for each input back to js code. */ public String[] toSourceArray() { return runInCompilerThread(new Callable<String[]>() { public String[] call() throws Exception { Tracer tracer = newTracer("toSourceArray"); try { int numInputs = inputs_.length; String[] sources = new String[numInputs]; CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs_[i].getAstRoot(Compiler.this); cb.reset(); toSource(cb, i, scriptNode); sources[i] = cb.toString(); } return sources; } finally { stopTracer(tracer, "toSourceArray"); } } }); } /** * Converts the parse tree for a module back to js code. */ public String toSource(final JSModule module) { return runInCompilerThread(new Callable<String>() { public String call() throws Exception { List<CompilerInput> inputs = module.getInputs(); int numInputs = inputs.size(); if (numInputs == 0) { return ""; } CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.get(i).getAstRoot(Compiler.this); if (scriptNode == null) { throw new IllegalArgumentException( "Bad module: " + module.getName()); } toSource(cb, i, scriptNode); } return cb.toString(); } }); } /** * Converts the parse tree for each input in a module back to js code. */ public String[] toSourceArray(final JSModule module) { return runInCompilerThread(new Callable<String[]>() { public String[] call() throws Exception { List<CompilerInput> inputs = module.getInputs(); int numInputs = inputs.size(); if (numInputs == 0) { return new String[0]; } String[] sources = new String[numInputs]; CodeBuilder cb = new CodeBuilder(); for (int i = 0; i < numInputs; i++) { Node scriptNode = inputs.get(i).getAstRoot(Compiler.this); if (scriptNode == null) { throw new IllegalArgumentException( "Bad module input: " + inputs.get(i).getName()); } cb.reset(); toSource(cb, i, scriptNode); sources[i] = cb.toString(); } return sources; } }); } /** * Writes out js code from a root node. If printing input delimiters, this * method will attach a comment to the start of the text indicating which * input the output derived from. If there were any preserve annotations * within the root's source, they will also be printed in a block comment * at the beginning of the output. */ public void toSource(final CodeBuilder cb, final int inputSeqNum, final Node root) { runInCompilerThread(new Callable<Void>() { public Void call() throws Exception { if (options_.printInputDelimiter) { if ((cb.getLength() > 0) && !cb.endsWith("\n")) { cb.append("\n"); // Make sure that the label starts on a new line } Preconditions.checkState(root.getType() == Token.SCRIPT); String delimiter = options_.inputDelimiter; String sourceName = (String)root.getProp(Node.SOURCENAME_PROP);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> this; } /** Returns all text in the text buffer. */ @Override public String toString() { return sb.toString(); } /** Returns the length of the text buffer. */ public int getLength() { return sb.length(); } /** Returns the (zero-based) index of the last line in the text buffer. */ int getLineIndex() { return lineCount; } /** Returns the (zero-based) index of the last column in the text buffer. */ int getColumnIndex() { int index = sb.lastIndexOf("\n"); return (index >= 0) ? sb.length() - (index + 1) : sb.length(); } /** Determines whether the text ends with the given suffix. */ boolean endsWith(String suffix) { return (sb.length() > suffix.length()) && suffix.equals(sb.substring(sb.length() - suffix.length())); } } //------------------------------------------------------------------------ // Optimizations //------------------------------------------------------------------------ public void optimize() { PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker); if (options_.devMode == DevMode.EVERY_PASS) { phaseOptimizer.setSanityCheck(sanityCheck); } phaseOptimizer.consume(getPassConfig().getOptimizations()); phaseOptimizer.process(externsRoot, jsRoot); if (hasErrors()) { return; } } @Override void setCssRenamingMap(CssRenamingMap map) { options_.cssRenamingMap = map; } @Override CssRenamingMap getCssRenamingMap() { return options_.cssRenamingMap; } /** * Reprocesses the current defines over the AST. This is used by GwtCompiler * to generate N outputs for different targets from the same (checked) AST. * For each target, we apply the target-specific defines by calling * {@code processDefines} and then {@code optimize} to optimize the AST * specifically for that target. */ public void processDefines() { (new DefaultPassConfig(options_)).processDefines.create(this) .process(externsRoot, jsRoot); } boolean isInliningForbidden() { return options_.propertyRenaming == PropertyRenamingPolicy

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.HEURISTIC || options_.propertyRenaming == PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC; } /** Control Flow Analysis. */ ControlFlowGraph<Node> computeCFG() { logger_.info("Computing Control Flow Graph"); Tracer tracer = newTracer("computeCFG"); ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true); process(cfa); stopTracer(tracer, "computeCFG"); return cfa.getCfg(); } public void normalize() { logger_.info("Normalizing"); startPass("normalize"); process(new Normalize(this, false)); setNormalized(); endPass(); } @Override void prepareAst(Node root) { Tracer tracer = newTracer("prepareAst"); CompilerPass pass = new PrepareAst(this); pass.process(null, root); stopTracer(tracer, "prepareAst"); } void recordFunctionInformation() { logger_.info("Recording function information"); startPass("recordFunctionInformation"); RecordFunctionInformation recordFunctionInfoPass = new RecordFunctionInformation( this, getPassConfig().getIntermediateState().functionNames); process(recordFunctionInfoPass); functionInformationMap_ = recordFunctionInfoPass.getMap(); endPass(); } protected final CodeChangeHandler.RecentChange recentChange = new CodeChangeHandler.RecentChange(); private final List<CodeChangeHandler> codeChangeHandlers = Lists.<CodeChangeHandler>newArrayList(); @Override void addChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.add(handler); } @Override void removeChangeHandler(CodeChangeHandler handler) { codeChangeHandlers.remove(handler); } /** * All passes should call reportCodeChange() when they alter * the JS tree structure. This is verified by CompilerTestCase. * This allows us to optimize to a fixed point. */ @Override public void reportCodeChange() { for (CodeChangeHandler handler : codeChangeHandlers) { handler.reportChange(); } } @Override public CodingConvention getCodingConvention() { CodingConvention convention = options_.getCodingConvention(); convention = convention != null ? convention : defaultCodingConvention; return convention; } @Override public boolean isIdeMode()

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(str); debugLog_.append('\n'); logger_.fine(str); } private SourceFile getSourceFileByName(String sourceName) { if (inputsByName_.containsKey(sourceName)) { return inputsByName_.get(sourceName).getSourceFile(); } return null; } public String getSourceLine(String sourceName, int lineNumber) { if (lineNumber < 1) { return null; } SourceFile input = getSourceFileByName(sourceName); if (input != null) { return input.getLine(lineNumber); } return null; } public Region getSourceRegion(String sourceName, int lineNumber) { if (lineNumber < 1) { return null; } SourceFile input = getSourceFileByName(sourceName); if (input != null) { return input.getRegion(lineNumber); } return null; } //------------------------------------------------------------------------ // Package-private helpers //------------------------------------------------------------------------ @Override Node getNodeForCodeInsertion(JSModule module) { if (module == null) { if (inputs_.length == 0) { throw new IllegalStateException("No inputs"); } return inputs_[0].getAstRoot(this); } List<CompilerInput> inputs = module.getInputs(); if (inputs.size() > 0) { return inputs.get(0).getAstRoot(this); } for (JSModule m : getModuleGraph().getTransitiveDepsDeepestFirst(module)) { inputs = m.getInputs(); if (inputs.size() > 0) { return inputs.get(0).getAstRoot(this); } } throw new IllegalStateException("Root module has no inputs"); } public SourceMap getSourceMap() { return sourceMap_; } VariableMap getVariableMap() { return getPassConfig().getIntermediateState().variableMap; } VariableMap getPropertyMap() { return getPassConfig().getIntermediateState().propertyMap; } CompilerOptions getOptions() { return options_; } FunctionInformationMap getFunctionalInformationMap() { return functionInformationMap_; } /** * Sets the logging level for the com.google.javascript.jscomp package. */ public static void set

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.parsing.ParserRunner; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.io.IOException; import java.util.logging.Logger; /** * Generates an AST for a JavaScript source file. * * */ public class JsAst implements SourceAst { private static final Logger logger_ = Logger.getLogger(JsAst.class.getName()); private static final long serialVersionUID = 1L; private transient SourceFile sourceFile; private String fileName; private Node root; public JsAst(SourceFile sourceFile) { this.sourceFile = sourceFile; this.fileName = sourceFile.getName(); } @Override public Node getAstRoot(AbstractCompiler compiler) { if (root == null) { createAst(compiler); } return root; } @Override public void clearAst() { root = null; // While we're at it, clear out any saved text in the source file on // the assumption that if we're dumping the parse tree, then we probably // assume regenerating everything else is a smart idea also. sourceFile.clearCachedSource(); } @Override public SourceFile getSourceFile() { return sourceFile; } @Override public void setSourceFile(SourceFile file) { Preconditions.checkState(fileName.equals(file.getName())); sourceFile = file; } private void createAst(AbstractCompiler compiler)

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { try { parse(compiler, sourceFile.getName(), sourceFile.getCode()); } catch (IOException e) { compiler.report( JSError.make(AbstractCompiler.READ_ERROR, sourceFile.getName())); } } private void parse(AbstractCompiler compiler, String sourceName, String sourceStr) { try { logger_.fine("Parsing: " + sourceName); root = ParserRunner.parse(sourceName, sourceStr, compiler.getParserConfig(), compiler.getDefaultErrorReporter(), logger_); } catch (IOException e) { compiler.report(JSError.make(AbstractCompiler.READ_ERROR, sourceName)); } if (root == null || compiler.hasHaltingErrors()) { // There was a parse error or IOException, so use a dummy block. root = new Node(Token.BLOCK); } else { compiler.prepareAst(root); } // Set the source name so that the compiler passes can track // the source file and module. root.putProp(Node.SOURCENAME_PROP, sourceName); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>String propertyName) { return hasProperty(propertyName); } /** Returns the names of all the properties directly on this type. */ public Set<String> getOwnPropertyNames() { return new HashSet<String>(); } /** * Checks whether the property's type is inferred. */ public abstract boolean isPropertyTypeInferred(String propertyName); /** * Checks whether the property's type is declared. */ public abstract boolean isPropertyTypeDeclared(String propertyName); /** * Whether the given property is declared on this object. */ boolean hasOwnDeclaredProperty(String name) { return hasOwnProperty(name) && isPropertyTypeDeclared(name); } /** Checks whether the property was defined in the externs. */ public boolean isPropertyInExterns(String propertyName) { return false; } /** * Gets the number of properties of this object. */ public abstract int getPropertiesCount(); /** * Returns a list of properties defined or inferred on this type and any of * its supertypes. */ public Set<String> getPropertyNames() { Set<String> props = Sets.newHashSet(); collectPropertyNames(props); return props; } /** * Adds any properties defined on this type or its supertypes to the set. */ abstract void collectPropertyNames(Set<String> props); @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseObjectType(this); } /** * Checks that the prototype is an implicit prototype of this object. Since * each object has an implicit prototype, an implicit prototype's * implicit prototype is also this implicit prototype's. * * @param prototype any prototype based object * * @return {@code true} if {@code prototype} is {@code equal} to any * object in this object's implicit prototype chain. */ final boolean isImplicitPrototype(ObjectType prototype) { for (ObjectType current = this; current != null; current = current.getImplicitPrototype()) { if (current.equals(prototype)) { return true; } } return false; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.TRUE; } /** * We treat this as the unknown

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> type if any of its implicit prototype * properties is unknown. */ @Override public boolean isUnknownType() { // If the object is unknown now, check the supertype again, // because it might have been resolved since the last check. if (unknown) { ObjectType implicitProto = getImplicitPrototype(); if (implicitProto == null || implicitProto.isNativeObjectType()) { unknown = false; } else { unknown = implicitProto.isUnknownType(); } } return unknown; } @Override public boolean isObject() { return true; } /** * Returns true if any cached valeus have been set for this type. If true, * then the prototype chain should not be changed, as it might invalidate the * cached values. */ public boolean hasCachedValues() { return !unknown; } /** Whether this is a built-in object. */ public boolean isNativeObjectType() { return false; } /** * A null-safe version of JSType#toObjectType. */ public static ObjectType cast(JSType type) { return type == null ? null : type.toObjectType(); } /** * Gets the interfaces implemented by the ctor associated with this type. * Intended to be overridden by subclasses. */ public Iterable<ObjectType> getCtorImplementedInterfaces() { return ImmutableSet.of(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.Set; /** * Group a set of related diagnostic types together, so that they can * be toggled on and off as one unit. * @author nicksantos@google.com (Nick Santos) */ public class DiagnosticGroup { // The set of types represented by this group, hashed by key. private final Set<DiagnosticType> types; /** * Create a group that matches all errors of the given types. */ public DiagnosticGroup(DiagnosticType ...types) { this.types = ImmutableSet.copyOf(Arrays.asList(types)); } /** * Create a diagnostic group with no name that only matches the given type. */ private DiagnosticGroup(DiagnosticType type) { this.types = ImmutableSet.of(type); } // DiagnosticGroups with only a single DiagnosticType. private static final Map<DiagnosticType, DiagnosticGroup> singletons = Maps.newHashMap(); /** Create a diagnostic group that matches only the given type. */ static DiagnosticGroup forType(DiagnosticType type) { if (!singletons.containsKey(type)) { singletons.put(type, new DiagnosticGroup(type)); } return singletons.get(type); } /** * Create a composite group. */ public DiagnosticGroup(Diagnostic

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Group ...groups) { Set<DiagnosticType> set = Sets.newHashSet(); for (DiagnosticGroup group : groups) { set.addAll(group.types); } this.types = ImmutableSet.copyOf(set); } /** * Returns whether the given error's type matches a type * in this group. */ public boolean matches(JSError error) { return matches(error.getType()); } /** * Returns whether the given type matches a type in this group. */ public boolean matches(DiagnosticType type) { return types.contains(type); } /** * Returns whether all of the types in the given group are in this group. */ boolean isSubGroup(DiagnosticGroup group) { for (DiagnosticType type : group.types) { if (!matches(type)) { return false; } } return true; } /** * Returns an iterator over all the types in this group. */ Collection<DiagnosticType> getTypes() { return types; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> /** * Create a named type based on the reference. */ public NamedType(JSTypeRegistry registry, String reference, String sourceName, int lineno, int charno) { super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE)); Preconditions.checkNotNull(reference); this.reference = reference; this.sourceName = sourceName; this.lineno = lineno; this.charno = charno; } @Override public void forgiveUnknownNames() { forgiving = true; } /** Returns the type to which this refers (which is unknown if unresolved). */ public JSType getReferencedType() { return referencedType; } @Override public String getReferenceName() { return reference; } @Override public String toString() { return reference; } @Override public boolean hasReferenceName() { return true; } @Override public boolean isNamedType() { return true; } @Override public boolean isNominalType() { return true; } /** * Two named types are equal if they are the same {@code ObjectType} object. * This is complicated by the fact that equals is sometimes called before we * have a chance to resolve the type names. * * @return {@code true} iff {@code that} == {@code this} or {@code that} * is a {@link NamedType} whose reference is the same as ours, * or {@code that} is the type we reference. */ @Override public boolean equals(Object that) { if (this == that) { return true; } else if (that instanceof JSType) { ObjectType objType = ObjectType.cast((JSType) that); if (objType != null) { return objType.isNominalType() && reference.equals(objType.getReferenceName()); } } return false; } @Override public int hashCode() { return reference.hashCode(); } /** * Resolve the referenced type within the enclosing scope. */ @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) { // TODO(user): Investigate whether it is really necessary to keep two // different

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.JSType; /** * <p>The syntactic scope creator scans the parse tree to create a Scope object * containing all the variable declarations in that scope.</p> * * <p>This implementation is not thread-safe.</p> * * */ class SyntacticScopeCreator implements ScopeCreator { private final AbstractCompiler compiler; private Scope scope; private String sourceName; private final RedeclarationHandler redeclarationHandler; // The arguments variable is special, in that it's declared in every local // scope, but not explicitly declared. private static final String ARGUMENTS = "arguments"; public static final DiagnosticType VAR_MULTIPLY_DECLARED_ERROR = DiagnosticType.error( "JSC_VAR_MULTIPLY_DECLARED_ERROR", "Variable {0} first declared in {1}"); /** * Creates a ScopeCreator. */ SyntacticScopeCreator(AbstractCompiler compiler) { this.compiler = compiler; this.redeclarationHandler = new DefaultRedeclarationHandler(); } SyntacticScopeCreator( AbstractCompiler compiler, RedeclarationHandler redeclarationHandler) { this.compiler = compiler; this.redeclarationHandler = redeclarationHandler; } public Scope createScope(Node n, Scope parent) { sourceName =

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> null; if (parent == null) { scope = new Scope(n, compiler); } else { scope = new Scope(parent, n); } scanRoot(n, parent); sourceName = null; Scope returnedScope = scope; scope = null; return returnedScope; } private void scanRoot(Node n, Scope parent) { if (n.getType() == Token.FUNCTION) { sourceName = (String) n.getProp(Node.SOURCENAME_PROP); final Node fnNameNode = n.getFirstChild(); final Node args = fnNameNode.getNext(); final Node body = args.getNext(); // Bleed the function name into the scope, if it hasn't // been declared in the outer scope. String fnName = fnNameNode.getString(); if (!fnName.isEmpty() && NodeUtil.isFunctionAnonymous(n)) { declareVar(fnName, fnNameNode, n, null, null, n); } // Args: Declare function variables Preconditions.checkState(args.getType() == Token.LP); for (Node a = args.getFirstChild(); a != null; a = a.getNext()) { Preconditions.checkState(a.getType() == Token.NAME); declareVar(a.getString(), a, args, n, null, n); } // Body scanVars(body, n); } else { // It's the global block Preconditions.checkState(scope.getParent() == null); scanVars(n, null); } } /** * Scans and gather variables declarations under a Node */ private void scanVars(Node n, Node parent) { switch (n.getType()) { case Token.VAR: // Declare all variables. e.g. var x = 1, y, z; for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); Preconditions.checkState(child.getType() == Token.NAME); String name = child.getString(); declareVar(name, child, n, parent, null, n); child = next; } return; case Token.FUNCTION: if (NodeUtil.isFunctionAnonymous(n)) { return; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> String fnName = n.getFirstChild().getString(); if (fnName.isEmpty()) { // This is invalid, but allow it so the checks can catch it. return; } declareVar(fnName, n.getFirstChild(), n, parent, null, n); return; // should not examine function's children case Token.CATCH: Preconditions.checkState(n.getChildCount() == 3); Preconditions.checkState(n.getFirstChild().getType() == Token.NAME); // the first child is the catch var and the third child // is the code block final Node var = n.getFirstChild(); final Node block = var.getNext().getNext(); declareVar(var.getString(), var, n, parent, null, n); scanVars(block, n); return; // only one child to scan case Token.SCRIPT: sourceName = (String) n.getProp(Node.SOURCENAME_PROP); break; } // Variables can only occur in statement-level nodes, so // we only need to traverse children in a couple special cases. if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) { for (Node child = n.getFirstChild(); child != null;) { Node next = child.getNext(); scanVars(child, n); child = next; } } } /** * Interface for injectable duplicate handling. */ interface RedeclarationHandler { void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber); } /** * The default handler for duplicate declarations. */ private class DefaultRedeclarationHandler implements RedeclarationHandler { public void onRedeclaration( Scope s, String name, Node n, Node parent, Node gramps, Node nodeWithLineNumber) { // Don't allow multiple variables to be declared at the top level scope if (scope.isGlobal()) { Scope.Var origVar = scope.getVar(name); Node origParent = origVar.getParentNode(); if (origParent.getType() == Token.CATCH && parent.getType() == Token.CATCH) { // Okay, both are 'catch(x)' variables. return

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>; } boolean allowDupe = false; JSDocInfo info = n.getJSDocInfo(); if (info == null) { info = parent.getJSDocInfo(); } allowDupe = info != null && info.getSuppressions().contains("duplicate"); if (!allowDupe) { compiler.report( JSError.make(sourceName, nodeWithLineNumber, VAR_MULTIPLY_DECLARED_ERROR, name, (origVar.input != null ? origVar.input.getName() : "??"))); } } } } /** * Declares a variable. * * @param name The variable name * @param n The node corresponding to the variable name (usually a NAME node) * @param parent The parent node of {@code n} * @param gramps The parent node of {@code parent} * @param declaredType The variable's type, according to JSDoc * @param nodeWithLineNumber The node to use to access the line number of * the variable declaration, if needed */ private void declareVar(String name, Node n, Node parent, Node gramps, JSType declaredType, Node nodeWithLineNumber) { if (scope.isDeclared(name, false) || (scope.isLocal() && name.equals(ARGUMENTS))) { redeclarationHandler.onRedeclaration( scope, name, n, parent, gramps, nodeWithLineNumber); } else { scope.declare(name, n, declaredType, compiler.getInput(sourceName)); } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.ObjectType; import java.nio.charset.Charset; /** * A code generator that outputs type annotations for functions and * constructors. * */ class TypedCodeGenerator extends CodeGenerator { TypedCodeGenerator(CodeConsumer consumer, Charset outputCharset) { super(consumer, outputCharset, true); } @Override void add(Node n, Context context) { Node parent = n.getParent(); if (parent.getType() == Token.BLOCK || parent.getType() == Token.SCRIPT) { if (n.getType() == Token.FUNCTION) { add(getFunctionAnnotation(n)); } else if (n.getType() == Token.EXPR_RESULT && n.getFirstChild().getType() == Token.ASSIGN) { Node rhs = n.getFirstChild().getFirstChild(); add(getTypeAnnotation(rhs)); } else if (n.getType() == Token.VAR && n.getFirstChild().getFirstChild() != null && n.getFirstChild().getFirstChild().getType() == Token.FUNCTION) { add(getFunctionAnnotation(n.getFirstChild().getFirstChild())); } } super.add(n, context); } private String getTypeAnnotation(Node node) { JSType type = node.getJSType();

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> if (type instanceof FunctionType) { return getFunctionAnnotation(node); } else if (type != null && !type.isUnknownType() && !type.isEmptyType() && !type.isVoidType()) { return "/** @type {" + node.getJSType() + "} */\n"; } else { return ""; } } /** * @param node A node for a function for which to generate a type annotation */ private String getFunctionAnnotation(Node node) { StringBuilder sb = new StringBuilder("/**\n"); if (node.getJSType().isUnknownType()) { return ""; } FunctionType funType = (FunctionType) node.getJSType(); // We need to use the child nodes of the function as the nodes for the // parameters of the function type do not have the real parameter names. // FUNCTION // NAME // LP // NAME param1 // NAME param2 Node fnNode = funType.getSource(); if (fnNode != null) { Node paramNode = NodeUtil.getFnParameters(fnNode).getFirstChild(); // Param types for (Node n : funType.getParameters()) { // Bail out if the paramNode is not there. if (paramNode == null) { break; } sb.append(" * @param {" + n.getJSType() + "} "); sb.append(paramNode.getString()); sb.append("\n"); paramNode = paramNode.getNext(); } } // Return type JSType retType = funType.getReturnType(); if (retType != null && !retType.isUnknownType() && !retType.isEmptyType()) { sb.append(" * @return {" + retType + "}\n"); } // Constructor/interface if (funType.isConstructor() || funType.isInterface()) { ObjectType superInstance = funType.getSuperClassConstructor().getInstanceType(); if (!superInstance.toString().equals("Object")) { sb.append(" * @extends {" + superInstance + "}\n"); } for (ObjectType interfaze : funType.getImplementedInterfaces()) { sb.append(" * @implements {" + interfaze + "}\n"); }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>) { return referencedType.canAssignTo(that); } @Override public boolean equals(Object that) { if (this == that) { return true; } return referencedType.equals(that); } @Override public int hashCode() { return referencedType.hashCode(); } @Override public String toString() { return referencedType.toString(); } @Override public ObjectType getImplicitPrototype() { return referencedType.getImplicitPrototype(); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { return referencedType.defineProperty(propertyName, type, inferred, inExterns); } @Override public boolean isPropertyTypeDeclared(String propertyName) { return referencedType.isPropertyTypeDeclared(propertyName); } @Override public boolean isPropertyTypeInferred(String propertyName) { return referencedType.isPropertyTypeInferred(propertyName); } @Override public boolean isPropertyInExterns(String propertyName) { return referencedType.isPropertyInExterns(propertyName); } @Override public int getPropertiesCount() { return referencedType.getPropertiesCount(); } @Override protected void collectPropertyNames(Set<String> props) { referencedType.collectPropertyNames(props); } @Override public JSType findPropertyType(String propertyName) { return referencedType.findPropertyType(propertyName); } @Override public JSType getPropertyType(String propertyName) { return referencedType.getPropertyType(propertyName); } @Override public JSDocInfo getJSDocInfo() { return referencedType.getJSDocInfo(); } @Override public void setJSDocInfo(JSDocInfo info) { referencedType.setJSDocInfo(info); } @Override public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) { return referencedType.getOwnPropertyJSDocInfo(propertyName); } @Override public void setPropertyJSDocInfo(String propertyName, JSDocInfo info, boolean inExterns) { referencedType.setPropertyJSDocInfo(propertyName, info, inExterns); } @Override public boolean hasProperty(String propertyName) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> return referencedType.hasProperty(propertyName); } @Override public boolean hasOwnProperty(String propertyName) { return referencedType.hasOwnProperty(propertyName); } @Override public Set<String> getOwnPropertyNames() { return referencedType.getOwnPropertyNames(); } @Override public FunctionType getConstructor() { return referencedType.getConstructor(); } @Override public JSType getParameterType() { return referencedType.getParameterType(); } @Override public JSType getIndexType() { return referencedType.getIndexType(); } @Override public <T> T visit(Visitor<T> visitor) { return referencedType.visit(visitor); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { referencedType = (ObjectType) referencedType.resolve(t, scope); return this; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.jscomp.NodeTraversal.ScopedCallback; import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.JSDocInfo.Visibility; import com.google.javascript.rhino.jstype.JSType; import com.google.javascript.rhino.jstype.FunctionPrototypeType; import com.google.javascript.rhino.jstype.FunctionType; import com.google.javascript.rhino.jstype.ObjectType; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; /** * A compiler pass that checks that the programmer has obeyed all the access * control restrictions indicated by JSDoc annotations, like * {@code @private} and {@code @deprecated}. * * There are two parts to this pass: * 1) JSDoc Inference: Attaching the appropriate JSDoc to * all programmer-defined types and properties. * 2) Access Control Enforcement: Emitting warnings when the code does not * obey the restrictions attached to JSTypes in step 1. * * Because access control restrictions are attached to type information, * it's important that TypeCheck runs before this pass, so that all types * are correctly resolved and propagated before this pass runs. * * @author nicksantos@google.com (Nick Santos) */ class CheckAccessControls implements ScopedCallback

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> private JSType currentClass = null; CheckAccessControls(AbstractCompiler compiler) { this.compiler = compiler; this.validator = compiler.getTypeValidator(); } public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, this); } public void enterScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth++; } if (methodDepth == 0) { currentClass = getClassOfMethod(n, parent); } methodDepth++; } } public void exitScope(NodeTraversal t) { if (!t.inGlobalScope()) { Node n = t.getScopeRoot(); Node parent = n.getParent(); if (isDeprecatedFunction(n, parent)) { deprecatedDepth--; } methodDepth--; if (methodDepth == 0) { currentClass = null; } } } /** * Gets the type of the class that "owns" a method, or null if * we know that its un-owned. */ private JSType getClassOfMethod(Node n, Node parent) { if (parent.getType() == Token.ASSIGN) { Node lValue = parent.getFirstChild(); if (lValue.isQualifiedName()) { if (lValue.getType() == Token.GETPROP) { // We have an assignment of the form "a.b = ...". JSType lValueType = lValue.getJSType(); if (lValueType != null && lValueType.isConstructor()) { // If a.b is a constructor, then everything in this function // belongs to the "a.b" type. return ((FunctionType) lValueType).getInstanceType(); } else { // If a.b is not a constructor, then treat this as a method // of whatever type is on "a". return normalizeClassType(lValue.getFirstChild().getJSType()); } } else { // We have an assignment of the form "a = ...", so pull the // type off the "a". return normalizeClassType(lValue.getJSType()); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } else if (NodeUtil.isFunctionDeclaration(n) || parent.getType() == Token.NAME) { return normalizeClassType(n.getJSType()); } return null; } /** * Normalize the type of a constructor, its instance, and its prototype * all down to the same type (the instance type). */ private JSType normalizeClassType(JSType type) { if (type == null || type.isUnknownType()) { return type; } else if (type.isConstructor()) { return ((FunctionType) type).getInstanceType(); } else if (type.isFunctionPrototypeType()) { FunctionType owner = ((FunctionPrototypeType) type).getOwnerFunction(); if (owner.isConstructor()) { return owner.getInstanceType(); } } return type; } public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) { return true; } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.NAME: checkNameDeprecation(t, n, parent); checkNameVisibility(t, n, parent); break; case Token.GETPROP: checkPropertyDeprecation(t, n, parent); checkPropertyVisibility(t, n, parent); break; case Token.NEW: checkConstructorDeprecation(t, n, parent); break; } } /** * Checks the given NEW node to ensure that access restrictions are obeyed. */ private void checkConstructorDeprecation(NodeTraversal t, Node n, Node parent) { JSType type = n.getJSType(); if (type != null) { String deprecationInfo = getTypeDeprecationInfo(type); if (deprecationInfo != null && shouldEmitDeprecationWarning(t, n, parent)) { if (!deprecationInfo.isEmpty()) { compiler.report( JSError.make(t, n, DEPRECATED_CLASS_REASON, type.toString(), deprecationInfo)); } else { compiler.report( JSError.make(t, n, DEPRECATED_CLASS, type.toString())); } } } } /** * Checks the given NAME node to ensure that access restrictions are obeyed. */ private

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>NodeTraversal t, Node name, Node parent) { Var var = t.getScope().getVar(name.getString()); if (var != null) { JSDocInfo docInfo = var.getJSDocInfo(); if (docInfo != null) { // If a name is private, make sure that we're in the same file. Visibility visibility = docInfo.getVisibility(); if (visibility == Visibility.PRIVATE && !t.getInput().getName().equals(docInfo.getSourceName())) { if (docInfo.isConstructor() && isValidPrivateConstructorAccess(parent)) { return; } compiler.report( JSError.make(t, name, BAD_PRIVATE_GLOBAL_ACCESS, name.getString(), docInfo.getSourceName())); } } } } /** * Determines whether the given property is visible in the current context. * @param t The current traversal. * @param getprop The getprop node. */ private void checkPropertyVisibility(NodeTraversal t, Node getprop, Node parent) { ObjectType objectType = ObjectType.cast(dereference(getprop.getFirstChild().getJSType())); String propertyName = getprop.getLastChild().getString(); if (objectType != null) { // Is this a normal property access, or are we trying to override // an existing property? boolean isOverride = t.inGlobalScope() && parent.getType() == Token.ASSIGN && parent.getFirstChild() == getprop; // Find the lowest property defined on a class with visibility // information. if (isOverride) { objectType = objectType.getImplicitPrototype(); } JSDocInfo docInfo = null; for (; objectType != null; objectType = objectType.getImplicitPrototype()) { docInfo = objectType.getOwnPropertyJSDocInfo(propertyName); if (docInfo != null && docInfo.getVisibility() != Visibility.INHERITED) { break; } } if (objectType == null) { // We couldn't find a visibility modifier; assume it's public. return; } boolean sameInput = t.getInput().getName().equals(docInfo.getSourceName()); Visibility visibility = docInfo.getVisibility(); JSType owner

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } /** * Whether the given access of a private constructor is legal. * * For example, * new PrivateCtor_(); // not legal * PrivateCtor_.newInstance(); // legal * x instanceof PrivateCtor_ // legal * * This is a weird special case, because our visibility system is inherited * from Java, and JavaScript has no distinction between classes and * constructors like Java does. * * We may want to revisit this if we decide to make the restrictions tighter. */ private static boolean isValidPrivateConstructorAccess(Node parent) { return parent.getType() != Token.NEW; } /** * Determines whether a deprecation warning should be emitted. * @param t The current traversal. * @param n The node which we are checking. * @param parent The parent of the node which we are checking. */ private boolean shouldEmitDeprecationWarning( NodeTraversal t, Node n, Node parent) { // In the global scope, there are only two kinds of accesses that should // be flagged for warnings: // 1) Calls of deprecated functions and methods. // 2) Instantiations of deprecated classes. // For now, we just let everything else by. if (t.inGlobalScope()) { if (!((parent.getType() == Token.CALL && parent.getFirstChild() == n) || n.getType() == Token.NEW)) { return false; } } // We can always assign to a deprecated property, to keep it up to date. if (n.getType() == Token.GETPROP && n == parent.getFirstChild() && NodeUtil.isAssignmentOp(parent)) { return false; } return !canAccessDeprecatedTypes(t); } /** * Returns whether it's currently ok to access deprecated names and * properties. * * There are 3 exceptions when we're allowed to use a deprecated * type or property: * 1) When we're in a deprecated function. * 2) When we're in a deprecated class. * 3) When we're in a static method of a deprecated class. */ private boolean canAccessDeprecatedTypes(NodeTraversal t) { Node scopeRoot = t.getScopeRoot(); Node scopeRootParent = scopeRoot.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>_LOCALE_CONSTANT_NAME = "goog.LOCALE"; // Compiler errors when invalid combinations of passes are run. static final DiagnosticType TIGHTEN_TYPES_WITHOUT_TYPE_CHECK = DiagnosticType.error("JSC_TIGHTEN_TYPES_WITHOUT_TYPE_CHECK", "TightenTypes requires type checking. Please use --check_types."); static final DiagnosticType CANNOT_USE_PROTOTYPE_AND_VAR = DiagnosticType.error("JSC_CANNOT_USE_PROTOTYPE_AND_VAR", "Rename prototypes and inline variables cannot be used together"); // Miscellaneous errors. static final DiagnosticType REPORT_PATH_IO_ERROR = DiagnosticType.error("JSC_REPORT_PATH_IO_ERROR", "Error writing compiler report to {0}"); private static final DiagnosticType INPUT_MAP_PROP_PARSE = DiagnosticType.error("JSC_INPUT_MAP_PROP_PARSE", "Input property map parse error: {0}"); private static final DiagnosticType INPUT_MAP_VAR_PARSE = DiagnosticType.error("JSC_INPUT_MAP_VAR_PARSE", "Input variable map parse error: {0}"); /** * A global namespace to share across checking passes. * TODO(nicksantos): This is a hack until I can get the namespace into * the symbol table. */ private GlobalNamespace namespaceForChecks = null; /** * A type-tightener to share across optimization passes. */ private TightenTypes tightenTypes = null; /** Names exported by goog.exportSymbol. */ private Set<String> exportedNames = null; /** * Ids for cross-module method stubbing, so that each method has * a unique id. */ private CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator = new CrossModuleMethodMotion.IdGenerator(); /** * Keys are arguments passed to getCssName() found during compilation; values * are the number of times the key appeared as an argument to getCssName(). */ private Map<String, Integer> cssNames = null; /** The variable renaming map */ private VariableMap variableMap = null; /** The property renaming map */ private VariableMap propertyMap = null; /** The naming map for anonymous functions */

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> private VariableMap anonymousFunctionNameMap = null; /** Fully qualified function names and globally unique ids */ private FunctionNames functionNames = null; public DefaultPassConfig(CompilerOptions options) { super(options); } @Override State getIntermediateState() { return new State( cssNames == null ? null : Maps.newHashMap(cssNames), exportedNames == null ? null : Collections.unmodifiableSet(exportedNames), crossModuleIdGenerator, variableMap, propertyMap, anonymousFunctionNameMap, functionNames); } @Override void setIntermediateState(State state) { this.cssNames = state.cssNames == null ? null : Maps.newHashMap(state.cssNames); this.exportedNames = state.exportedNames == null ? null : Sets.newHashSet(state.exportedNames); this.crossModuleIdGenerator = state.crossModuleIdGenerator; this.variableMap = state.variableMap; this.propertyMap = state.propertyMap; this.anonymousFunctionNameMap = state.anonymousFunctionNameMap; this.functionNames = state.functionNames; } @Override protected List<PassFactory> getChecks() { List<PassFactory> checks = Lists.newArrayList(); if (options.nameAnonymousFunctionsOnly) { if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { checks.add(nameMappedAnonymousFunctions); } else if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { checks.add(nameUnmappedAnonymousFunctions); } return checks; } if (options.checkSuspiciousCode) { checks.add(suspiciousCode); } if (options.checkControlStructures) { checks.add(checkControlStructures); } if (options.checkRequires.isOn()) { checks.add(checkRequires); } if (options.checkProvides.isOn()) { checks.add(checkProvides); } // The following passes are more like "preprocessor" passes. // It's important that they run before most checking passes. // Perhaps this method should be renamed? if (options.generateExports) { checks.add(generateExports); } if (options.exportTestFunctions) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> checks.add(exportTestFunctions); } if (options.closurePass) { checks.add(closurePrimitives.makeOneTimePass()); } if (options.closurePass && options.checkMissingGetCssNameLevel.isOn()) { checks.add(closureCheckGetCssName); } if (options.closurePass) { checks.add(closureReplaceGetCssName); } if (options.syntheticBlockStartMarker != null) { // This pass must run before the first fold constants pass. checks.add(createSyntheticBlocks); } // All passes must run the variable check. This synthesizes // variables later so that the compiler doesn't crash. It also // checks the externs file for validity. If you don't want to warn // about missing variable declarations, we shut that specific // error off. WarningsGuard warningsGuard = options.getWarningsGuard(); if (!options.checkSymbols && (warningsGuard == null || !warningsGuard.disables( DiagnosticGroups.CHECK_VARIABLES))) { options.setWarningLevel(DiagnosticGroups.CHECK_VARIABLES, CheckLevel.OFF); } checks.add(checkVars); if (options.checkShadowVars.isOn()) { checks.add(checkShadowVars); } if (options.aggressiveVarCheck.isOn()) { checks.add(checkVariableReferences); } // This pass should run before types are assigned. if (options.processObjectPropertyString) { checks.add(objectPropertyStringPreprocess); } // DiagnosticGroups override the plain checkTypes option. if (options.enables(DiagnosticGroups.CHECK_TYPES)) { options.checkTypes = true; } else if (options.disables(DiagnosticGroups.CHECK_TYPES)) { options.checkTypes = false; } // Type-checking already does more accurate method arity checking, so don't // do legacy method arity checking unless checkTypes is OFF. if (options.checkTypes) { checks.add(resolveTypes.makeOneTimePass()); checks.add(inferTypes.makeOneTimePass()); checks.add(checkTypes.makeOneTimePass()); } else { if (options.checkFunctions.isOn()) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> checks.add(checkFunctions); } if (options.checkMethods.isOn()) { checks.add(checkMethods); } } if (options.checkUnreachableCode.isOn() || (options.checkTypes && options.checkMissingReturn.isOn())) { checks.add(checkControlFlow); } // CheckAccessControls only works if check types is on. if (options.enables(DiagnosticGroups.ACCESS_CONTROLS) && options.checkTypes) { checks.add(checkAccessControls); } if (options.checkGlobalNamesLevel.isOn()) { checks.add(checkGlobalNames); } if (options.checkUndefinedProperties.isOn() || options.checkUnusedPropertiesEarly) { checks.add(checkSuspiciousProperties); } if (options.checkCaja || options.checkEs5Strict) { checks.add(checkStrictMode); } // Defines in code always need to be processed. checks.add(processDefines); if (options.instrumentationTemplate != null || options.recordFunctionInformation) { checks.add(computeFunctionNames); } assertAllOneTimePasses(checks); return checks; } @Override protected List<PassFactory> getOptimizations() { List<PassFactory> passes = Lists.newArrayList(); // TODO(nicksantos): The order of these passes makes no sense, and needs // to be re-arranged. if (options.runtimeTypeCheck) { passes.add(runtimeTypeCheck); } passes.add(createEmptyPass("beforeStandardOptimizations")); if (!options.idGenerators.isEmpty()) { passes.add(replaceIdGenerators); } // Optimizes references to the arguments variable. if (options.optimizeArgumentsArray) { passes.add(optimizeArgumentsArray); } // Remove all parameters that are constants or unused. if (options.optimizeParameters) { passes.add(removeUselessParameters); } // Abstract method removal works best on minimally modified code, and also // only needs to run once. if (options.closurePass && options.removeAbstractMethods) { passes.add(removeAbstractMethods); } // Collapsing properties can undo constant

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> inlining, so we do this before // the main optimization loop. if (options.collapseProperties) { passes.add(collapseProperties); } // Tighten types based on actual usage. if (options.tightenTypes) { passes.add(tightenTypesBuilder); } // Property disambiguation should only run once and needs to be done // soon after type checking, both so that it can make use of type // information and so that other passes can take advantage of the renamed // properties. if (options.disambiguateProperties) { passes.add(disambiguateProperties); } if (options.computeFunctionSideEffects) { passes.add(markPureFunctions); } else if (options.markNoSideEffectCalls) { // TODO(user) The properties that this pass adds to CALL and NEW // AST nodes increase the AST's in-memory size. Given that we are // already running close to our memory limits, we could run into // trouble if we end up using the @nosideeffects annotation a lot // or compute @nosideeffects annotations by looking at function // bodies. It should be easy to propagate @nosideeffects // annotations as part of passes that depend on this property and // store the result outside the AST (which would allow garbage // collection once the pass is done). passes.add(markNoSideEffectCalls); } if (options.chainCalls) { passes.add(chainCalls); } // Constant checking must be done after property collapsing because // property collapsing can introduce new constants (e.g. enum values). if (options.inlineConstantVars) { passes.add(checkConsts); } // The Caja library adds properties to Object.prototype, which breaks // most for-in loops. This adds a check to each loop that skips // any property matching /___$/. if (options.ignoreCajaProperties) { passes.add(ignoreCajaProperties); } assertAllOneTimePasses(passes); if (options.smartNameRemoval || options.reportPath != null) { passes.addAll(getCodeRemovingPasses()); passes.add(smartNamePass); } // TODO(user): This forces a

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> first crack at crossModuleCodeMotion // before devirtualization. Once certain functions are devirtualized, // it confuses crossModuleCodeMotion ability to recognized that // it is recursive. // TODO(user): This is meant for a temporary quick win. // In the future, we might want to improve our analysis in // CrossModuleCodeMotion so we don't need to do this. if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } // Method devirtualization benefits from property disambiguiation so // it should run after that pass but before passes that do // optimizations based on global names (like cross module code motion // and inline functions). Smart Name Removal does better if run before // this pass. if (options.devirtualizePrototypeMethods) { passes.add(devirtualizePrototypeMethods); } if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.BEFORE_OPTIMIZATION_LOOP)); } passes.add(createEmptyPass("beforeMainOptimizations")); passes.addAll(getMainOptimizationLoop()); passes.add(createEmptyPass("beforeModuleMotion")); if (options.crossModuleCodeMotion) { passes.add(crossModuleCodeMotion); } if (options.crossModuleMethodMotion) { passes.add(crossModuleMethodMotion); } passes.add(createEmptyPass("afterModuleMotion")); // Some optimizations belong outside the loop because running them more // than once would either have no benefit or be incorrect. if (options.customPasses != null) { passes.add(getCustomPasses( CustomPassExecutionTime.AFTER_OPTIMIZATION_LOOP)); } if (options.flowSensitiveInlineVariables) { passes.add(flowSensitiveInlineVariables); // After inlining some of the variable uses, some variables are unused. // Re-run remove unused vars to clean it up. if (options.removeUnusedVars) { passes.add(removeUnusedVars); } } if (options.collapseAnonymousFunctions) { passes.add(collapseAnonymousFunctions); } // Move functions before extracting prototype member declarations. if (options.moveFunctionDeclarations) { passes

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.add(moveFunctionDeclarations); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) { passes.add(nameMappedAnonymousFunctions); } // The mapped name anonymous function pass makes use of information that // the extract prototype member declarations pass removes so the former // happens before the latter. // // Extracting prototype properties screws up the heuristic renaming // policies, so never run it when those policies are requested. if (options.extractPrototypeMemberDeclarations && (options.propertyRenaming != PropertyRenamingPolicy.HEURISTIC && options.propertyRenaming != PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC)) { passes.add(extractPrototypeMemberDeclarations); } if (options.coalesceVariableNames) { passes.add(coalesceVariableNames); } if (options.ambiguateProperties && (options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED)) { passes.add(ambiguateProperties); } if (options.propertyRenaming != PropertyRenamingPolicy.OFF) { passes.add(renameProperties); } // Reserve global names added to the "windows" object. if (options.reserveRawExports) { passes.add(gatherRawExports); } // This comes after property renaming because quoted property names must // not be renamed. if (options.convertToDottedProperties) { passes.add(convertToDottedProperties); } // Property renaming must happen before this pass runs since this // pass may convert dotted properties into quoted properties. It // is beneficial to run before alias strings, alias keywords and // variable renaming. if (options.rewriteFunctionExpressions) { passes.add(rewriteFunctionExpressions); } // This comes after converting quoted property accesses to dotted property // accesses in order to avoid aliasing property names. if (!options.aliasableStrings.isEmpty() || options.aliasAllStrings) { passes.add(aliasStrings); } if (options.aliasExternals) { passes.add(aliasExternals); } if (options.aliasKeywords) { passes.add(aliasKeywords); } if (options.collapseVariableDeclarations) { passes.add(collapseVariableDeclarations);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } passes.add(denormalize); if (options.instrumentationTemplate != null) { passes.add(instrumentFunctions); } if (options.variableRenaming != VariableRenamingPolicy.ALL) { // If we're leaving some (or all) variables with their old names, // then we need to undo any of the markers we added for distinguishing // local variables ("$$1"). passes.add(invertContextualRenaming); } if (options.variableRenaming != VariableRenamingPolicy.OFF) { passes.add(renameVars); } // This pass should run after names stop changing. if (options.processObjectPropertyString) { passes.add(objectPropertyStringPostprocess); } if (options.labelRenaming) { passes.add(renameLabels); } if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) { passes.add(nameUnmappedAnonymousFunctions); } // Safety check if (options.checkSymbols) { passes.add(sanityCheckVars); } return passes; } /** Creates the passes for the main optimization loop. */ private List<PassFactory> getMainOptimizationLoop() { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineGetters) { passes.add(inlineGetters); } passes.addAll(getCodeRemovingPasses()); if (options.inlineFunctions || options.inlineLocalFunctions) { passes.add(inlineFunctions); } if (options.removeUnusedVars) { if (options.deadAssignmentElimination) { passes.add(deadAssignmentsElimination); } passes.add(removeUnusedVars); } assertAllLoopablePasses(passes); return passes; } /** Creates several passes aimed at removing code. */ private List<PassFactory> getCodeRemovingPasses() { List<PassFactory> passes = Lists.newArrayList(); if (options.inlineVariables || options.inlineLocalVariables) { passes.add(inlineVariables); } else if (options.inlineConstantVars) { passes.add(inlineConstants); } if (options.removeConstantExpressions) { passes.add(removeConstantExpressions); } if

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (options.foldConstants) { // These used to be one pass. passes.add(minimizeExitPoints); passes.add(foldConstants); } if (options.removeDeadCode) { passes.add(removeUnreachableCode); } if (options.removeUnusedPrototypeProperties) { passes.add(removeUnusedPrototypeProperties); } assertAllLoopablePasses(passes); return passes; } /** * Checks for code that is probably wrong (such as stray expressions). */ // TODO(bolinfest): Write a CompilerPass for this. final PassFactory suspiciousCode = new PassFactory("suspiciousCode", true) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { List<Callback> sharedCallbacks = Lists.newArrayList(); sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING)); sharedCallbacks.add(new CheckSideEffects(CheckLevel.WARNING)); if (options.checkGlobalThisLevel.isOn()) { sharedCallbacks.add( new CheckGlobalThis(compiler, options.checkGlobalThisLevel)); } return combineChecks(compiler, sharedCallbacks); } }; /** Verify that all the passes are one-time passes. */ private void assertAllOneTimePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(pass.isOneTimePass()); } } /** Verify that all the passes are multi-run passes. */ private void assertAllLoopablePasses(List<PassFactory> passes) { for (PassFactory pass : passes) { Preconditions.checkState(!pass.isOneTimePass()); } } /** Checks for validity of the control structures. */ private final PassFactory checkControlStructures = new PassFactory("checkControlStructures", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new ControlStructureCheck(compiler); } }; /** Checks that all constructed classes are goog.require()d. */ private final PassFactory checkRequires = new PassFactory("checkRequires", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckRequiresForConstructors(compiler, options.checkRequires

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>); } }; /** Makes sure @constructor is paired with goog.provides(). */ private final PassFactory checkProvides = new PassFactory("checkProvides", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckProvides(compiler, options.checkProvides); } }; private static final DiagnosticType GENERATE_EXPORTS_ERROR = DiagnosticType.error( "JSC_GENERATE_EXPORTS_ERROR", "Exports can only be generated if export symbol/property " + "functions are set."); /** Generates exports for @export annotations. */ private final PassFactory generateExports = new PassFactory("generateExports", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null && convention.getExportPropertyFunction() != null) { return new GenerateExports(compiler, convention.getExportSymbolFunction(), convention.getExportPropertyFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Generates exports for functions associated with JSUnit. */ private final PassFactory exportTestFunctions = new PassFactory("exportTestFunctions", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { CodingConvention convention = compiler.getCodingConvention(); if (convention.getExportSymbolFunction() != null) { return new ExportTestFunctions(compiler, convention.getExportSymbolFunction()); } else { return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR); } } }; /** Raw exports processing pass. */ final PassFactory gatherRawExports = new PassFactory("gatherRawExports", false) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { final GatherRawExports pass = new GatherRawExports( compiler); return new CompilerPass() { @Override public void process(Node externs, Node root) { pass.process(externs, root); if (exportedNames == null) { exportedNames = Sets.newHashSet(); } exportedNames.addAll(pass.getExportedVariableNames()); } }; } }; /** Closure pre

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(AbstractCompiler compiler) { return new GlobalTypeResolver(compiler); } }; /** Rusn type inference. */ private final PassFactory inferTypes = new PassFactory("inferTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); makeTypeInference(compiler).process(externs, root); } }; } }; /** Checks type usage */ private final PassFactory checkTypes = new PassFactory("checkTypes", false) { @Override protected CompilerPass createInternal(final AbstractCompiler compiler) { return new CompilerPass() { @Override public void process(Node externs, Node root) { Preconditions.checkNotNull(topScope); Preconditions.checkNotNull(typedScopeCreator); TypeCheck check = makeTypeCheck(compiler); check.process(externs, root); compiler.getErrorManager().setTypedPercent(check.getTypedPercent()); } }; } }; /** * Checks possible execution paths of the program for problems: missing return * statements and dead code. */ private final PassFactory checkControlFlow = new PassFactory("checkControlFlow", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { List<Callback> callbacks = Lists.newArrayList(); if (options.checkUnreachableCode.isOn()) { callbacks.add( new CheckUnreachableCode(compiler, options.checkUnreachableCode)); } if (options.checkMissingReturn.isOn() && options.checkTypes) { callbacks.add( new CheckMissingReturn(compiler, options.checkMissingReturn)); } return combineChecks(compiler, callbacks); } }; /** Checks access controls. Depends on type-inference. */ private final PassFactory checkAccessControls = new PassFactory("checkAccessControls", true) { @Override protected CompilerPass createInternal(AbstractCompiler compiler) { return new CheckAccessControls(compiler); } }; /** Executes the given callbacks with a {@link CombinedCompilerPass}. */ private static CompilerPass combineChecks(AbstractCompiler compiler, List<Callback

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC || options.propertyRenaming == PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC; } /** Create a compiler pass that runs the given passes in serial. */ private static CompilerPass runInSerial(final CompilerPass ... passes) { return runInSerial(Lists.newArrayList(passes)); } /** Create a compiler pass that runs the given passes in serial. */ private static CompilerPass runInSerial( final Collection<CompilerPass> passes) { return new CompilerPass() { @Override public void process(Node externs, Node root) { for (CompilerPass pass : passes) { pass.process(externs, root); } } }; } @VisibleForTesting static Map<String, Node> getAdditionalReplacements( CompilerOptions options) { Map<String, Node> additionalReplacements = Maps.newHashMap(); if (options.markAsCompiled || options.closurePass) { additionalReplacements.put(COMPILED_CONSTANT_NAME, new Node(Token.TRUE)); } if (options.closurePass && options.locale != null) { additionalReplacements.put(CLOSURE_LOCALE_CONSTANT_NAME, Node.newString(options.locale)); } return additionalReplacements; } /** A compiler pass that marks pure functions. */ private static class PureFunctionMarker implements CompilerPass { private final AbstractCompiler compiler; private final String reportPath; private final boolean useNameReferenceGraph; PureFunctionMarker(AbstractCompiler compiler, String reportPath, boolean useNameReferenceGraph) { this.compiler = compiler; this.reportPath = reportPath; this.useNameReferenceGraph = useNameReferenceGraph; } @Override public void process(Node externs, Node root) { DefinitionProvider definitionProvider = null; if (useNameReferenceGraph) { NameReferenceGraphConstruction graphBuilder = new NameReferenceGraphConstruction(compiler); graphBuilder.process(externs, root); definitionProvider = graphBuilder.getNameReferenceGraph(); } else { SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler); defFinder.process(externs, root); definitionProvider = defFinder; } PureFunction

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> determining provided dependencies amongst different * js scripts. */ public String extractClassNameIfProvide(Node node, Node parent); /** * Convenience method for determining required dependencies amongst different * js scripts. */ public String extractClassNameIfRequire(Node node, Node parent); /** * Function name used when exporting properties. * Signature: fn(object, publicName, symbol). * @return function name. */ public String getExportPropertyFunction(); /** * Function name used when exporting symbols. * Signature: fn(publicPath, object). * @return function name. */ public String getExportSymbolFunction(); /** * Checks if the given CALL node is forward-declaring any types, * and returns the name of the types if it is. */ public List<String> identifyTypeDeclarationCall(Node n); /** * Checks if the given ASSIGN node is a typedef, and returns the * name of the type if it is. */ public String identifyTypeDefAssign(Node n); /** * In many JS libraries, the function that produces inheritance also * adds properties to the superclass and/or subclass. */ public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type); /** * Function name for abstract methods. An abstract method can be assigned to * an interface method instead of an anonymous function in order to avoid * linter warnings produced by assigning a function without a return value * where a return value is expected. * @return function name. */ public String getAbstractMethodName(); /** * Checks if the given method defines a singleton getter, and if it does, * returns the name of the class with the singleton getter. By default, always * returns null. Meant to be overridden by subclasses. * * @param callNode A CALL node. */ public String getSingletonGetterClassName(Node callNode); /** * In many JS libraries, the function that adds a singleton getter to a class * adds properties to the class. */ public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType); public DelegateRelationship getDelegateRelationship(Node callNode); /** * In many JS libraries, the function that creates a delegate relationship * also adds properties to the deleg

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2004 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.javascript.rhino.Node; /** * Abstracted consumer of the CodeGenerator output. * * @see CodeGenerator * @see CodePrinter * @see InlineCostEstimator * * * */ abstract class CodeConsumer { boolean statementNeedsEnded = false; boolean statementStarted = false; boolean sawFunction = false; /** * Starts the source mapping for the given * node at the current position. */ void startSourceMapping(Node node) { } /** * Finishes the source mapping for the given * node at the current position. */ void endSourceMapping(Node node) { } /** * Generates the source map from the given code consumer, * appending the information it saved to the SourceMap * object given. */ void generateSourceMap(SourceMap map){ } /** * Returns the current length of the buffer in which * the generated code is being placed. */ abstract int getCurrentBufferLength(); /** * Returns the current character position on the current * line in the generated code. */ abstract int getCurrentCharIndex(); /** * Returns the current line in the generated code. */ abstract int getCurrentLineIndex(); /** * Provides a means of interrupting the CodeGenerator. Derived classes should * return false to stop further processing. */ boolean continueProcessing() { return true; } /** * Retrieve the last character of the last string sent to append. */ abstract char getLastChar(); void addIdentifier(String identifier) { add

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(identifier); } /** * Appends a string to the code, keeping track of the current line length. * * NOTE: the string must be a complete token--partial strings or * partial regexes will run the risk of being split across lines. * * Do not directly append newlines with this method. Instead use * {@link #startNewLine}. */ abstract void append(String str); void appendBlockStart() { append("{"); } void appendBlockEnd() { append("}"); } void startNewLine() { } void maybeLineBreak() { maybeCutLine(); } void maybeCutLine() { } void endLine() { } void notePreferredLineBreak() { } void beginBlock() { if (statementNeedsEnded) { append(";"); maybeLineBreak(); } appendBlockStart(); endLine(); statementNeedsEnded = false; } void endBlock() { endBlock(false); } void endBlock(boolean statementContext) { appendBlockEnd(); if (statementContext) { endLine(); } statementNeedsEnded = false; } void listSeparator() { add(","); maybeLineBreak(); } /** * Indicates the end of a statement and a ';' may need to be added. * But we don't add it now, in case we're at the end of a block (in which * case we don't have to add the ';'). * See maybeEndStatement() */ void endStatement() { endStatement(false); } void endStatement(boolean needSemiColon) { if (needSemiColon) { append(";"); maybeLineBreak(); statementNeedsEnded = false; } else if (statementStarted) { statementNeedsEnded = true; } } /** * This is to be called when we're in a statement. If the prev statement * needs to be ended, add a ';'. */ void maybeEndStatement() { // Add a ';' if we need to. if (statementNeedsEnded) { append(";"); maybeLineBreak(); endLine(); statementNeedsEnded = false; } statementStarted = true; } void endFunction() { endFunction(false

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>); } void endFunction(boolean statementContext) { sawFunction = true; if (statementContext) { endLine(); } } void beginCaseBody() { append(":"); } void endCaseBody() { } void add(String newcode) { maybeEndStatement(); if (newcode.length() == 0) { return; } char c = newcode.charAt(0); if ((isWordChar(c) || c == '\\') && isWordChar(getLastChar())) { // need space to separate. This is not pretty printing. // For example: "return foo;" append(" "); } append(newcode); } void appendOp(String op, boolean binOp) { append(op); } void addOp(String op, boolean binOp) { maybeEndStatement(); char first = op.charAt(0); char prev = getLastChar(); if ((first == '+' || first == '-') && prev == first) { // This is not pretty printing. This is to prevent misparsing of // things like "x + ++y" or "x++ + ++y" append(" "); } else if (Character.isLetter(first) && isWordChar(prev)) { // Make sure there is a space after e.g. instanceof , typeof append(" "); } else if (prev == '-' && first == '>') { // Make sure that we don't emit --> append(" "); } // Allow formating around the operator. appendOp(op, binOp); // Line breaking after an operator is always safe. Line breaking before an // operator on the other hand is not. We only line break after a bin op // because it looks strange. if (binOp) { maybeCutLine(); } } void addNumber(double x) { // This is not pretty printing. This is to prevent misparsing of x- -4 as // x--4 (which is a syntax error). char prev = getLastChar(); if (x < 0 && prev == '-') { add(" "); } if ((long) x == x) { long value = (long) x; long mantissa = value; int exp =

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> 0; if (x >= 100) { while (mantissa / 10 * Math.pow(10, exp + 1) == value) { mantissa /= 10; exp++; } } if (exp > 2) { add(Long.toString(mantissa) + "E" + Integer.toString(exp)); } else { add(Long.toString(value)); } } else { add(String.valueOf(x)); } } static boolean isWordChar(char ch) { return (ch == '_' || ch == '$' || Character.isLetterOrDigit(ch)); } /** * If the body of a for loop or the then clause of an if statement has * a single statement, should it be wrapped in a block? Doing so can * help when pretty-printing the code, and permits putting a debugging * breakpoint on the statement inside the condition. * * @return {@boolean true} if such expressions should be wrapped */ boolean shouldPreserveExtraBlocks() { return false; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> {@code UnionType} implements a common JavaScript idiom in which the * code is specifically designed to work with multiple input types. Because * JavaScript always knows the runtime type of an object value, this is safer * than a C union.<p> * * For instance, values of the union type {@code (String,boolean)} can be of * type {@code String} or of type {@code boolean}. The commutativity of the * statement is captured by making {@code (String,boolean)} and * {@code (boolean,String)} equal.<p> * * The implementation of this class prevents the creation of nested * unions.<p> */ public class UnionType extends JSType { private static final long serialVersionUID = 1L; Set<JSType> alternates; private final int hashcode; /** * Creates a union type. * * @param alternates the alternates of the union */ UnionType(JSTypeRegistry registry, Set<JSType> alternates) { super(registry); this.alternates = alternates; this.hashcode = this.alternates.hashCode(); } /** * Gets the alternate types of this union type. * @return The alternate types of this union type. The returned set is * immutable. */ public Iterable<JSType> getAlternates() { return alternates; } @Override public void forgiveUnknownNames() { for (JSType type : getAlternates()) { type.forgiveUnknownNames(); } } /** * This predicate is used to test whether a given type can appear in a * numeric context, such as an operand of a multiply operator. * * @return true if the type can appear in a numeric context. */ @Override public boolean matchesNumberContext() { // TODO(user): Reverse this logic to make it correct instead of generous. for (JSType t : alternates) { if (t.matchesNumberContext()) { return true; } } return false; } /** * This predicate is used to test whether a given type can appear in a * {@code String} context, such as an operand of a string concat ({@code +}) * operator.<p> *

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>JSType that) { boolean canAssign = true; for (JSType t : alternates) { if (t.isUnknownType()) { return true; } canAssign &= t.canAssignTo(that); } return canAssign; } @Override public boolean canBeCalled() { for (JSType t : alternates) { if (!t.canBeCalled()) { return false; } } return true; } @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); } @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; for (JSType t : alternates) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } return result; } /** * This predicate determines whether objects of this type can have the * {@code null} value, and therefore can appear in contexts where * {@code null} is expected. * * @return {@code true} for everything but {@code Number} and * {@code Boolean} types. */ @Override public boolean isNullable() { for (JSType t : alternates) { if (t.isNullable()) { return true; } } return false; } @Override public boolean isUnknownType() { for (JSType t : alternates) { if (t.isUnknownType()) { return true; } } return false; } @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType()) { for (JSType alternate : alternates) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } } } return getLeastSupertype(this, that); } JSType meet(JSType that) { UnionTypeBuilder builder

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> = new UnionTypeBuilder(registry); for (JSType alternate : alternates) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that instanceof UnionType) { for (JSType otherAlternate : ((UnionType) that).alternates) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && that.isObject()) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Two union types are equal if they have the same number of alternates * and all alternates are equal. */ @Override public boolean equals(Object object) { if (object instanceof UnionType) { UnionType that = (UnionType) object; return alternates.equals(that.alternates); } else { return false; } } @Override public int hashCode() { return this.hashcode; } @Override public boolean isUnionType() { return true; } @Override public boolean isObject() { for (JSType alternate : alternates) { if (!alternate.isObject()) { return false; } } return true; } /** * A {@link UnionType} contains a given type (alternate) iff the member * vector contains it. Since the {@link #equals} method above conforms to * the necessary semantics for the collection, everything works out just * fine. * * @param alternate The alternate which might be in this union. * * @return {@code true} if the alternate is in the union */ public boolean contains(JSType alternate) { return alternates.contains(alternate); } /** * Returns a more restricted union type than {@code this} one, in which all * subtypes of {@code type} have been removed.<p> * * Examples:

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * <ul> * <li>{@code (number,string)} restricted by {@code number} is * {@code string}</li> * <li>{@code (null, EvalError, URIError)} restricted by * {@code Error} is {@code null}</li> * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternates) { if (t.isUnknownType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); } @Override public String toString() { StringBuilder result = new StringBuilder(); boolean firstAlternate = true; result.append("("); SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA); sorted.addAll(alternates); for (JSType t : sorted) { if (!firstAlternate) { result.append("|"); } result.append(t.toString()); firstAlternate = false; } result.append(")"); return result.toString(); } @Override public boolean isSubtype(JSType that) { for (JSType element : alternates) { if (!element.isSubtype(that)) { return false; } } return true; } @Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { restricted.addAlternate( element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } return restricted.build(); } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { BooleanLiteralSet literals = BooleanLiteralSet.EMPTY; for (JSType element : alternates) { literals = literals.union(element.getPossibleToBooleanOutcomes()); if (literals == BooleanLiteralSet.BOTH) { break; } } return literals; } @Override public TypePair getTypesUnderEquality(JSType that) { UnionTypeBuilder thisRestricted = new

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderEquality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternates) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair( thisRestricted.build(), thatRestricted.build()); } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseUnionType(this); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { setResolvedTypeInternal(this); // for circularly defined types. boolean changed = false; ImmutableSet.Builder<JSType> resolvedTypes = ImmutableSet.builder(); for (JSType alternate : alternates)

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { JSType newAlternate = alternate.resolve(t, scope); changed |= (alternate != newAlternate); resolvedTypes.add(alternate); } if (changed) { Set<JSType> newAlternates = resolvedTypes.build(); Preconditions.checkState(newAlternates.hashCode() == this.hashcode); alternates = newAlternates; } return this; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } else { return getNativeType(JSTypeNative.NO_TYPE); } } public JSType caseAllType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseVoidType() { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } public JSType caseEnumElementType(EnumElementType type) { return type.getPrimitiveType().visit(this); } } NoObjectType(JSTypeRegistry registry) { super(registry, null, null, null, null, null, null, true, true); } @Override public JSType getReturnType() { return this; } @Override public ObjectType getInstanceType() { return this; } @Override public TernaryValue testForEquality(JSType that) { return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } else { return that.isObject() && !that.isNoType(); } } @Override public boolean isFunctionType() { return false; } @Override public boolean isNoObjectType() { return true; } @Override public JSType getLeastSupertype(JSType that) { return that.visit(leastSupertypeVisitor); } @Override public JSType getGreatestSubtype(JSType that) { return that.visit(greatestSubtypeVisitor); } @Override public ObjectType getImplicitPrototype() { return null; } @Override public String getReferenceName() { return null; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean equals(Object that) { return this == that; } @Override public int hashCode() { return System.identityHashCode(this); } @Override public int getPropertiesCount() { // Should never be called, returning the biggest number to highlight the // '

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>"; if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; if (d == 0.0) return "0"; if ((base < 2) || (base > 36)) { throw Context.reportRuntimeError1( "msg.bad.radix", Integer.toString(base)); } if (base != 10) { return DToA.JS_dtobasestr(base, d); } else { StringBuffer result = new StringBuffer(); DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d); return result.toString(); } } /** * If str is a decimal presentation of Uint32 value, return it as long. * Othewise return -1L; */ public static long testUint32String(String str) { // The length of the decimal string representation of // UINT32_MAX_VALUE, 4294967296 final int MAX_VALUE_LENGTH = 10; int len = str.length(); if (1 <= len && len <= MAX_VALUE_LENGTH) { int c = str.charAt(0); c -= '0'; if (c == 0) { // Note that 00,01 etc. are not valid Uint32 presentations return (len == 1) ? 0L : -1L; } if (1 <= c && c <= 9) { long v = c; for (int i = 1; i != len; ++i) { c = str.charAt(i) - '0'; if (!(0 <= c && c <= 9)) { return -1; } v = 10 * v + c; } // Check for overflow if ((v >>> 32) == 0) { return v; } } } return -1; } static boolean isSpecialProperty(String s) { return s.equals("__proto__") || s.equals("__parent__"); } // ------------------ // Statements // ------------------ public static String getMessage0(String messageId) { return getMessage(messageId, null);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Object messageHelper) { // XXX Use value for better error reporting String msg = (messageHelper == null) ? "null" : messageHelper.toString(); return typeError2("msg.isnt.function", msg, value == null ? "null" : value.getClass().getName()); } static int lastIndexResult(Context cx) { return cx.scratchIndex; } public static void storeUint32Result(Context cx, long value) { if ((value >>> 32) != 0) throw new IllegalArgumentException(); cx.scratchUint32 = value; } public static long lastUint32Result(Context cx) { long value = cx.scratchUint32; if ((value >>> 32) != 0) throw new IllegalStateException(); return value; } static String makeUrlForGeneratedScript (boolean isEval, String masterScriptUrl, int masterScriptLine) { if (isEval) { return masterScriptUrl+'#'+masterScriptLine+"(eval)"; } else { return masterScriptUrl+'#'+masterScriptLine+"(Function)"; } } static boolean isGeneratedScript(String sourceUrl) { // ALERT: this may clash with a valid URL containing (eval) or // (Function) return sourceUrl.indexOf("(eval)") >= 0 || sourceUrl.indexOf("(Function)") >= 0; } public static final Object[] emptyArgs = new Object[0]; public static final String[] emptyStrings = new String[0]; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bob Jervis * Google Inc. * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package com.google.javascript.rhino.jstype; /** * The {@code StaticSlot} interface must be implemented by variables that can * appear as members of a {@code StaticScope}. * * * * @param <T> The type of information stored about the slot */ public interface StaticSlot<T> { /** * Gets the name of the slot. */ String getName(); /** * Returns the type information, if any,

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Call(Node callNode) { return null; } @Override public boolean isSuperClassReference(String propertyName) { return false; } @Override public String extractClassNameIfProvide(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String extractClassNameIfRequire(Node node, Node parent) { String message = "only implemented in GoogleCodingConvention"; throw new UnsupportedOperationException(message); } @Override public String getExportPropertyFunction() { return null; } @Override public String getExportSymbolFunction() { return null; } @Override public List<String> identifyTypeDeclarationCall(Node n) { return null; } @Override public String identifyTypeDefAssign(Node n) { return null; } @Override public void applySubclassRelationship(FunctionType parentCtor, FunctionType childCtor, SubclassType type) { // do nothing } @Override public String getAbstractMethodName() { return null; } @Override public String getSingletonGetterClassName(Node callNode) { return null; } @Override public void applySingletonGetter(FunctionType functionType, FunctionType getterType, ObjectType objectType) { // do nothing. } @Override public DelegateRelationship getDelegateRelationship(Node callNode) { return null; } @Override public void applyDelegateRelationship( ObjectType delegateSuperclass, ObjectType delegateBase, ObjectType delegator, FunctionType delegateProxy, FunctionType findDelegate) { // do nothing. } @Override public String getDelegateSuperclassName() { return null; } @Override public void defineDelegateProxyProperties( JSTypeRegistry registry, Scope scope, Map<ObjectType, ObjectType> delegateProxyMap) { // do nothing. } @Override public String getGlobalObject() { return "window"; } @Override public boolean isPropertyTestFunction(Node call) { return false; } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { return null; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> fileName, Generator generator) { return new JSSourceFile(SourceFile.fromGenerator(fileName, generator)); } private SourceFile referenced; private JSSourceFile(SourceFile referenced) { super(referenced.getName()); this.referenced = referenced; } @Override public String getCode() throws IOException { return referenced.getCode(); } @Override public void clearCachedSource() { referenced.clearCachedSource(); } @Override @VisibleForTesting String getCodeNoCache() { return referenced.getCodeNoCache(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.collect.ImmutableSet; import com.google.javascript.jscomp.CheckLevel; import java.util.Set; /** * Abstract message formatter providing default behavior for implementations * of {@link MessageFormatter} needing a {@link SourceExcerptProvider}. * * */ public abstract class AbstractMessageFormatter implements MessageFormatter { private final SourceExcerptProvider source; private boolean colorize; public AbstractMessageFormatter(SourceExcerptProvider source) { this.source = source; } public void setColorize(boolean colorize) { this.colorize = colorize; } /** * Get the source excerpt provider. */ protected final SourceExcerptProvider getSource() { return source; } private static final Set<String> SUPPORTED_COLOR_TERMINALS = ImmutableSet.of("xterm", "xterm-color", "xterm-256color", "screen-bce"); static boolean termSupportsColor(String term) { return SUPPORTED_COLOR_TERMINALS.contains(term); } private static enum Color { ERROR("\033[31m"), WARNING("\033[35m"), RESET("\033[39m"); private final String controlCharacter; Color(String controlCharacter) { this.controlCharacter = controlCharacter; } public String getControlCharacter() { return controlCharacter; } } String getLevelName(CheckLevel level) { switch (level) { case ERROR: return maybeColor

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.javascript.jscomp.NodeTraversal.AbstractShallowCallback; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.io.IOException; import java.util.List; import java.util.Set; /** * A class for the internal representation of an input to the compiler. * Wraps a {@link SourceAst} and maintain state such as module for the input and * whether the input is an extern. Also calculates provided and required types. * * */ public class CompilerInput implements SourceAst { private static final long serialVersionUID = 1L; // Info about where the file lives. private JSModule module; private final boolean isExtern; final private String name; // The AST. private final SourceAst ast; // Provided and required symbols. private final Set<String> provides = Sets.newHashSet(); private final Set<String> requires = Sets.newHashSet(); public CompilerInput(SourceAst ast) { this(ast, ast.getSourceFile().getName(), false); } public CompilerInput(SourceAst ast, boolean isExtern) { this(ast, ast.getSourceFile().getName(), isExtern); } public CompilerInput(SourceAst ast, String inputName, boolean isExtern) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> this.ast = ast; this.name = inputName; this.isExtern = isExtern; } public CompilerInput(JSSourceFile file) { this(file, false); } public CompilerInput(JSSourceFile file, boolean isExtern) { this.ast = new JsAst(file); this.name = file.getName(); this.isExtern = isExtern; } /** Returns a name for this input. Must be unique across all inputs. */ public String getName() { return name; } @Override public Node getAstRoot(AbstractCompiler compiler) { return ast.getAstRoot(compiler); } @Override public void clearAst() { ast.clearAst(); } @Override public SourceFile getSourceFile() { return ast.getSourceFile(); } @Override public void setSourceFile(SourceFile file) { ast.setSourceFile(file); } /** Returns the SourceAst object on which this input is based. */ public SourceAst getSourceAst() { return ast; } /** Gets a list of types depended on by this input. */ public Set<String> getRequires(AbstractCompiler compiler) { if (getAstRoot(compiler) != null) { DepsFinder deps = new DepsFinder(compiler, true); NodeTraversal.traverse(compiler, getAstRoot(compiler), deps); requires.addAll(deps.types); return requires; } else { return ImmutableSet.<String>of(); } } /** Gets a list of types provided by this input. */ public Set<String> getProvides(AbstractCompiler compiler) { if (getAstRoot(compiler) != null) { DepsFinder deps = new DepsFinder(compiler, false); NodeTraversal.traverse(compiler, getAstRoot(compiler), deps); provides.addAll(deps.types); return provides; } else { return ImmutableSet.<String>of(); } } private class DepsFinder extends AbstractShallowCallback { private boolean findRequire; private List<String> types; private CodingConvention codingConvention; DepsFinder(AbstractCompiler compiler, boolean findRequire) { this.findRequire = findRequire; this.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>codingConvention = compiler.getCodingConvention(); this.types = Lists.newArrayList(); } public void visit(NodeTraversal t, Node n, Node parent) { switch (n.getType()) { case Token.CALL: String className = findRequire ? codingConvention.extractClassNameIfRequire(n, parent) : codingConvention.extractClassNameIfProvide(n, parent); if (className != null) { types.add(className); } break; } } } /** * Gets the source line for the indicated line number. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Does not include the newline at the end * of the file. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public String getLine(int lineNumber) { return getSourceFile().getLine(lineNumber); } /** * Get a region around the indicated line number. The exact definition of a * region is implementation specific, but it must contain the line indicated * by the line number. A region must not start or end by a carriage return. * * @param lineNumber the line number, 1 being the first line of the file. * @return The line indicated. Returns {@code null} if it does not exist, * or if there was an IO exception. */ public Region getRegion(int lineNumber) { return getSourceFile().getRegion(lineNumber); } public String getCode() throws IOException { return getSourceFile().getCode(); } /** Returns the module to which the input belongs. */ public JSModule getModule() { return module; } /** Sets the module to which the input belongs. */ public void setModule(JSModule module) { // An input may only belong to one module. Preconditions.checkArgument( module == null || this.module == null || this.module == module); this.module = module; } public boolean isExtern() { return isExtern; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>} */ public String format(CheckLevel level, MessageFormatter formatter) { switch (level) { case ERROR: return formatter.formatError(this); case WARNING: return formatter.formatWarning(this); default: return null; } } @Override public String toString() { // TODO(user): remove custom toString. return type.key + ". " + description + " at " + (sourceName != null && sourceName.length() > 0 ? sourceName : "(unknown source)") + " line " + (lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)"); } /** * Get the character number. */ public int getCharno() { return charno; } @Override public boolean equals(Object o) { // Generated by Intellij IDEA if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } JSError jsError = (JSError) o; if (charno != jsError.charno) { return false; } if (lineNumber != jsError.lineNumber) { return false; } if (!description.equals(jsError.description)) { return false; } if (level != jsError.level) { return false; } if (sourceName != null ? !sourceName.equals(jsError.sourceName) : jsError.sourceName != null) { return false; } if (!type.equals(jsError.type)) { return false; } return true; } @Override public int hashCode() { // Generated by Intellij IDEA int result = type.hashCode(); result = 31 * result + description.hashCode(); result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0); result = 31 * result + lineNumber; result = 31 * result + level.hashCode(); result = 31 * result + charno; return result; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>ThreadTrace()} to enable the * Tracer logging, otherwise Tracer does nothing. The requirement to call * {@code initCurrentThreadTrace} avoids the situtation where Tracer is called * without the explicit knowledge of the application authors because they * happen to use a class in another package that uses Tracer. If {@link * Tracer#logCurrentThreadTrace} is called without calling {@link * Tracer#initCurrentThreadTrace()}, then a Third Eye WARNING message is logged, * which should help track down the problem. * * */ final class Tracer { // package-private for access from unit tests static final Logger logger = Logger.getLogger(Tracer.class.getName()); /** * Whether pretty printing is enabled. This is intended to be set once * at application startup. */ private static volatile boolean defaultPrettyPrint; /* This list is guaranteed to only increase in length. It contains a list of additional * statistics that the user wants to keep track of. */ private static List<TracingStatistic> extraTracingStatistics = new CopyOnWriteArrayList<TracingStatistic>(); /** Values returned by extraTracingStatistics */ private long[] extraTracingValues; /** The type for grouping traces, may be null */ private final @Nullable String type; /** A comment string for the report */ private final String comment; /** Start time of the trace */ private final long startTimeMs; /** Stop time of the trace, non-final */ private long stopTimeMs; /** * Record our starter thread in order to trap Traces that are started in one * thread and stopped in another */ final Thread startThread; /** * We limit the number of events in a Trace in order to catch memory * leaks (a thread that keeps logging events and never clears them). * This number is arbitrary and can be increased if necessary (though * if there are more than 1000 events then the Tracer is probably being * misused). */ static final int MAX_TRACE_SIZE = 1000; /** * For unit testing. Can't use {@link com.google.common.time} because * this code is in base and has minimal dependencies. */ static interface InternalClock { long currentTimeMillis(); } /** *

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Construct a tracer whose type is based on the short name of the object * @param object Object to use as type name * @param comment A comment * @return new Tracer. */ static Tracer shortName(Object object, String comment) { if (object == null) { return new Tracer(comment); } return new Tracer(object.getClass().getSimpleName(), comment); } /** * Converts 'v' to a string and pads it with up to 16 spaces for * improved alignment. * @param v The value to convert. * @param digits_column_width The desired with of the string. */ private static String longToPaddedString(long v, int digits_column_width) { int digit_width = numDigits(v); StringBuilder sb = new StringBuilder(); appendSpaces(sb, digits_column_width - digit_width); sb.append(v); return sb.toString(); } /** * Gets the number of digits in an integer when printed in base 10. Assumes * a positive integer. * @param n The value. * @return The number of digits in the string. */ private static int numDigits(long n) { int i = 0; do { i++; n = n / 10; } while (n > 0); return i; } /** * Gets a string of spaces of the length specified. * @param sb The string builder to append to. * @param numSpaces The number of spaces in the string. */ @VisibleForTesting static void appendSpaces(StringBuilder sb, int numSpaces) { if (numSpaces > 16) { logger.warning("Tracer.appendSpaces called with large numSpaces"); // Avoid long loop in case some bug in the caller numSpaces = 16; } while (numSpaces >= 5) { sb.append(" "); numSpaces -= 5; } // We know it's less than 5 now switch (numSpaces) { case 1: sb.append(" "); break; case 2: sb.append(" "); break; case 3: sb.append("

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> "); break; case 4: sb.append(" "); break; } } /** * Adds a new tracing statistic to a trace * * @param tracingStatistic to enable a run * @return The index of this statistic (for use with stat.extraInfo()), or * -1 if the statistic is not enabled. */ static int addTracingStatistic(TracingStatistic tracingStatistic) { // Check to see if we can enable the tracing statistic before actually // adding it. if (tracingStatistic.enable()) { // No synchronization needed, since this is a copy-on-write array. extraTracingStatistics.add(tracingStatistic); // 99.9% of the time, this will be O(1) and return extraTracingStatistics.length - 1 return extraTracingStatistics.lastIndexOf(tracingStatistic); } else { return -1; } } /** * For testing purposes only. These removes all current tracers. Severe errors can occur * if there are any active tracers going on when this is called. * * The test suite uses this to remove any tracers that it has added. */ @VisibleForTesting static void clearTracingStatisticsTestingOnly() { extraTracingStatistics.clear(); } /** * Stop the trace. * This may only be done once and must be done from the same thread * that started it. * @param silence_threshold Traces for time less than silence_threshold * ms will be left out of the trace report. A value of -1 indicates * that the current ThreadTrace silence_threshold should be used. * @return The time that this trace actually ran */ long stop(int silence_threshold) { Preconditions.checkState(Thread.currentThread() == startThread); ThreadTrace trace = getThreadTrace(); // Do nothing if the thread trace was not initialized. if (!trace.isInitialized()) { return 0; } stopTimeMs = clock.currentTimeMillis(); if (extraTracingValues != null) { // We use extraTracingValues.length rather than extraTracingStatistics.size() because // a new statistic may have been added for (int i = 0; i < extraTracingValues.length; i++) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Statistics.get(i).getUnits()); sb.append("; "); } } } sb.append(indent); sb.append(tracer.toString()); return sb.toString(); } } /** Stores a thread's Trace */ static final class ThreadTrace { /** Events taking less than this number of milliseconds are not reported. */ int defaultSilenceThreshold; // non-final /** The Events corresponding to each startEvent/stopEvent */ final ArrayList<Event> events = new ArrayList<Event>(); /** Tracers that have not had their .stop() called */ final HashSet<Tracer> outstandingEvents = new HashSet<Tracer>(); /** Map from type to Stat object */ final Map<String, Stat> stats = new HashMap<String, Stat>(); /** * True if {@code outstandingEvents} has been cleared because we exceeded * the max trace limit. */ boolean isOutstandingEventsTruncated = false; /** * True if {@code events} has been cleared because we exceeded the max * trace limit. */ boolean isEventsTruncated = false; /** * Set to true if {@link Tracer#initCurrentThreadTrace()} was called by * the current thread. */ boolean isInitialized = false; /** * Whether pretty printing is enabled for the trace. */ boolean prettyPrint = false; /** Initialize the trace. */ void init() { isInitialized = true; } /** Is initialized? */ boolean isInitialized() { return isInitialized; } /** * Called by the constructor {@link Tracer#Tracer(String, String)} to create * a start event. */ void startEvent(Tracer t) { events.add(new Event(true, t)); boolean notAlreadyOutstanding = outstandingEvents.add(t); Preconditions.checkState(notAlreadyOutstanding); } /** * Called by {@link Tracer#stop()} to create a stop event. */ void endEvent(Tracer t, int silenceThreshold) { boolean wasOutstanding = outstandingEvents.remove(t); if (!wasOutstanding) { if (isOutstandingEventsTruncated) { // The events stack overflowed and was truncated, so just log a // warning. Otherwise, we get an exception which is extremely

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> // confusing. logger.log(Level.WARNING, "event not found, probably because the event stack " + "overflowed and was truncated", new Throwable()); } else { // throw an exception if the event was not found and the events stack // is pristine throw new IllegalStateException(); } } long elapsed = t.stopTimeMs - t.startTimeMs; if (silenceThreshold == -1) { // use default silenceThreshold = defaultSilenceThreshold; } if (elapsed < silenceThreshold) { // If this one is silent then we need to remove the start Event boolean removed = false; for (int i = 0; i < events.size(); i++) { Event e = events.get(i); if (e.tracer == t) { Preconditions.checkState(e.isStart); events.remove(i); removed = true; break; } } // Only assert if we didn't find the original and the events // weren't truncated. Preconditions.checkState(removed || isEventsTruncated); } else { events.add(new Event(false, t)); } if (t.type != null) { Stat stat = stats.get(t.type); if (stat == null) { stat = new Stat(); if (!extraTracingStatistics.isEmpty()) { stat.extraInfo = new int[extraTracingStatistics.size()]; } stats.put(t.type, stat); } stat.count++; if (typeToCountMap != null) { typeToCountMap.incrementBy(t.type, 1); } stat.clockTime += elapsed; if (typeToTimeMap != null) { typeToTimeMap.incrementBy(t.type, elapsed); } if (stat.extraInfo != null && t.extraTracingValues != null) { int overlapLength = Math.min(stat.extraInfo.length, t.extraTracingValues.length); for (int i = 0; i < overlapLength; i++) { stat.extraInfo[i] += t.extraTracingValues[i]; AtomicTracerStatMap map = extraTracingStatistics.get(i).getTracingStat(); if (map !=

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> null) { map.incrementBy(t.type, t.extraTracingValues[i]); } } } if (elapsed < silenceThreshold) { stat.silent++; if (typeToSilentMap != null) { typeToSilentMap.incrementBy(t.type, 1); } } } } boolean isEmpty() { return events.size() == 0 && outstandingEvents.size() == 0; } void truncateOutstandingEvents() { isOutstandingEventsTruncated = true; outstandingEvents.clear(); } void truncateEvents() { isEventsTruncated = true; events.clear(); } /** Produces the lovely Trace seen in the class comments */ // Nullness checker does not understand that prettyPrint => indent != null @SuppressWarnings("nullness") @Override public String toString() { int numDigits = getMaxDigits(); StringBuilder sb = new StringBuilder(); long etime = -1; LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null; for (Event e : events) { if (prettyPrint && !e.isStart && !indent.isEmpty()) { indent.pop(); } sb.append(" "); if (prettyPrint) { sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits)); } else { sb.append(e.toString(etime, "", 4)); } etime = e.eventTime(); sb.append('\n'); if (prettyPrint && e.isStart) { indent.push("| "); } } if (outstandingEvents.size() != 0) { long now = clock.currentTimeMillis(); sb.append(" Unstopped timers:\n"); for (Tracer t : outstandingEvents) { sb.append(" "). append(t). append(" ("). append(now - t.startTimeMs). append(" ms, started at "). append(formatTime(t.startTimeMs)). append(")\n"); } } for (String key : stats.keySet()) { Stat stat = stats.get(key); if (stat.count > 1) { sb.append(" TOTAL "). append(

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> path through // the code identical to how it's been for years. this.outputCharsetEncoder = null; } else { this.outputCharsetEncoder = outputCharset.newEncoder(); } } CodeGenerator(CodeConsumer consumer, Charset outputCharset) { this(consumer, outputCharset, true); } CodeGenerator(CodeConsumer consumer) { this(consumer, null, false); } void add(String str) { cc.add(str); } private void addIdentifier(String identifier) { cc.addIdentifier(identifierEscape(identifier)); } void add(Node n) { add(n, Context.OTHER); } void add(Node n, Context context) { if (!cc.continueProcessing()) { return; } int type = n.getType(); String opstr = NodeUtil.opToStr(type); int childCount = n.getChildCount(); Node first = n.getFirstChild(); Node last = n.getLastChild(); // Handle all binary operators if (opstr != null && first != last) { Preconditions.checkState(childCount == 2); int p = NodeUtil.precedence(type); addLeftExpr(first, p, context); cc.addOp(opstr, true); // For right-hand-side of operations, only pass context if it's // the IN_FOR_INIT_CLAUSE one. Context rhsContext = getContextForNoInOperator(context); // Handle associativity. // e.g. if the parse tree is a * (b * c), // we can simply generate a * b * c. if (last.getType() == type && NodeUtil.isAssociative(type)) { addExpr(last, p, rhsContext); } else if (NodeUtil.isAssignmentOp(n) && NodeUtil.isAssignmentOp(last)) { // Assignments are the only right-associative binary operators addExpr(last, p, rhsContext); } else { addExpr(last, p + 1, rhsContext); } return; } cc.startSourceMapping(n); switch (type) { case Token.TRY: { Preconditions.checkState(first.getNext().getType() ==

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Token.BLOCK && first.getNext().getChildCount() <= 1); Preconditions.checkState(childCount >= 2 && childCount <= 3); add("try"); add(first, Context.PRESERVE_BLOCK); // second child contains the catch block, or nothing if there // isn't a catch block Node catchblock = first.getNext().getFirstChild(); if (catchblock != null) { add(catchblock); } if (childCount == 3) { add("finally"); add(last, Context.PRESERVE_BLOCK); } break; } case Token.CATCH: Preconditions.checkState(childCount == 3); if (first.getNext().getType() != Token.EMPTY) { throw new Error("Catch conditions not suppored because I think" + " that it may be a netscape only feature."); } add("catch("); add(first); add(")"); add(last, Context.PRESERVE_BLOCK); break; case Token.THROW: Preconditions.checkState(childCount == 1); add("throw"); add(first); // Must have a ';' after a throw statement, otherwise safari can't // parse this. cc.endStatement(true); break; case Token.RETURN: add("return"); if (childCount == 1) { add(first); } else { Preconditions.checkState(childCount == 0); } cc.endStatement(); break; case Token.VAR: if (first != null) { add("var "); addList(first, false, getContextForNoInOperator(context)); } break; case Token.NAME: if (first == null || first.getType() == Token.EMPTY) { addIdentifier(n.getString()); } else { Preconditions.checkState(childCount == 1); addIdentifier(n.getString()); cc.addOp("=", true); if (first.getType() == Token.COMMA) { addExpr(first, NodeUtil.precedence(Token.ASSIGN)); } else { // Add expression, consider nearby code at lowest level of // precedence. addExpr(first, 0, getContextForNoInOperator

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>(context)); } } break; case Token.ARRAYLIT: add("["); addList(first, (int[]) n.getProp(Node.SKIP_INDEXES_PROP)); add("]"); break; case Token.LP: add("("); addList(first); add(")"); break; case Token.COMMA: addList(first, false, context); break; case Token.NUMBER: Preconditions.checkState(childCount == 0); cc.addNumber(n.getDouble()); break; case Token.TYPEOF: case Token.VOID: case Token.NOT: case Token.BITNOT: case Token.POS: case Token.NEG: { // All of these unary operators are right-associative Preconditions.checkState(childCount == 1); cc.addOp(NodeUtil.opToStrNoFail(type), false); addExpr(first, NodeUtil.precedence(type)); break; } case Token.HOOK: { Preconditions.checkState(childCount == 3); int p = NodeUtil.precedence(type); addLeftExpr(first, p + 1, context); cc.addOp("?", true); addExpr(first.getNext(), p); cc.addOp(":", true); addExpr(last, p); break; } case Token.REGEXP: if (first.getType() != Token.STRING || last.getType() != Token.STRING) { throw new Error("Expected children to be strings"); } String regexp = regexpEscape(first.getString(), outputCharsetEncoder); // I only use one .add because whitespace matters if (childCount == 2) { add(regexp + last.getString()); } else { Preconditions.checkState(childCount == 1); add(regexp); } break; case Token.GET_REF: add(first); break; case Token.REF_SPECIAL: Preconditions.checkState(childCount == 1); add(first); add("."); add((String) n.getProp(Node.NAME_PROP)); break; case Token.FUNCTION: Preconditions.checkState(childCount == 3);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> boolean funcNeedsParens = (context == Context.START_OF_EXPR); if (funcNeedsParens) { add("("); } add("function"); add(first); add(first.getNext()); add(last, Context.PRESERVE_BLOCK); cc.endFunction(context == Context.STATEMENT); if (funcNeedsParens) { add(")"); } break; case Token.SCRIPT: case Token.BLOCK: { boolean stripBlock = n.isSyntheticBlock() || ((context != Context.PRESERVE_BLOCK) && (n.getChildCount() < 2)); if (!stripBlock) { cc.beginBlock(); } for (Node c = first; c != null; c = c.getNext()) { add(c, Context.STATEMENT); // VAR doesn't include ';' since it gets used in expressions if (c.getType() == Token.VAR) { cc.endStatement(); } if (c.getType() == Token.FUNCTION) { cc.maybeLineBreak(); } // Prefer to break lines in between top-level statements // because top level statements are more homogeneous. if (type == Token.SCRIPT) { cc.notePreferredLineBreak(); } } if (!stripBlock) { cc.endBlock(context == Context.STATEMENT); } break; } case Token.FOR: if (childCount == 4) { add("for("); if (first.getType() == Token.VAR) { add(first, Context.IN_FOR_INIT_CLAUSE); } else { addExpr(first, 0, Context.IN_FOR_INIT_CLAUSE); } add(";"); add(first.getNext()); add(";"); add(first.getNext().getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { Preconditions.checkState(childCount == 3); add("for("); add(first); add("in"); add(first.getNext()); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } break

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>; case Token.DO: Preconditions.checkState(childCount == 2); add("do"); addNonEmptyExpression(first, Context.OTHER, false); add("while("); add(last); add(")"); cc.endStatement(); break; case Token.WHILE: Preconditions.checkState(childCount == 2); add("while("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.EMPTY: Preconditions.checkState(childCount == 0); break; case Token.GETPROP: { Preconditions.checkState(childCount == 2); Preconditions.checkState(last.getType() == Token.STRING); boolean needsParens = (first.getType() == Token.NUMBER); if (needsParens) { add("("); } addLeftExpr(first, NodeUtil.precedence(type), context); if (needsParens) { add(")"); } add("."); addIdentifier(last.getString()); break; } case Token.GETELEM: Preconditions.checkState(childCount == 2); addLeftExpr(first, NodeUtil.precedence(type), context); add("["); add(first.getNext()); add("]"); break; case Token.WITH: Preconditions.checkState(childCount == 2); add("with("); add(first); add(")"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); break; case Token.INC: case Token.DEC: { Preconditions.checkState(childCount == 1); String o = type == Token.INC ? "++" : "--"; int postProp = n.getIntProp(Node.INCRDECR_PROP, 0); // A non-zero post-prop value indicates a post inc/dec, default of zero // is a pre-inc/dec. if (postProp != 0) { addLeftExpr(first, NodeUtil.precedence(type), context); cc.addOp(o, false); } else { cc.addOp(o, false);

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> add(first); } break; } case Token.CALL: // If the left hand side of the call is a direct reference to eval, // then it must have a DIRECT_EVAL annotation. If it does not, then // that means it was originally an indirect call to eval, and that // indirectness must be preserved. if (first.getType() == Token.NAME && "eval".equals(first.getString()) && !first.getBooleanProp(Node.DIRECT_EVAL)) { add("(0,eval)"); } else { addLeftExpr(first, NodeUtil.precedence(type), context); } add("("); addList(first.getNext()); add(")"); break; case Token.IF: boolean hasElse = childCount == 3; boolean ambiguousElseClause = context == Context.BEFORE_DANGLING_ELSE && !hasElse; if (ambiguousElseClause) { cc.beginBlock(); } add("if("); add(first); add(")"); if (hasElse) { addNonEmptyExpression( first.getNext(), Context.BEFORE_DANGLING_ELSE, false); add("else"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), false); } else { addNonEmptyExpression(first.getNext(), Context.OTHER, false); Preconditions.checkState(childCount == 2); } if (ambiguousElseClause) { cc.endBlock(); } break; case Token.NULL: case Token.THIS: case Token.FALSE: case Token.TRUE: Preconditions.checkState(childCount == 0); add(Node.tokenToName(type)); break; case Token.CONTINUE: Preconditions.checkState(childCount <= 1); add("continue"); if (childCount == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.DEBUGGER: Preconditions.checkState(childCount == 0); add("debugger"); cc.endStatement(); break; case Token.BREAK: Preconditions.checkState(childCount <= 1); add("break"); if (childCount

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> == 1) { add(" "); add(first); } cc.endStatement(); break; case Token.EXPR_VOID: case Token.EXPR_RESULT: if (type == Token.EXPR_VOID && validation) { throw new Error("Unexpected EXPR_VOID. Should be EXPR_RESULT."); } Preconditions.checkState(childCount == 1); add(first, Context.START_OF_EXPR); cc.endStatement(); break; case Token.NEW: add("new "); int precedence = NodeUtil.precedence(type); // If the first child contains a CALL, then claim higher precedence // to force parens. Otherwise, when parsed, NEW will bind to the // first viable parens if (NodeUtil.containsCall(first)) { precedence = NodeUtil.precedence(first.getType()) + 1; } addExpr(first, precedence); // '()' is optional when no arguments are present Node next = first.getNext(); if (next != null) { add("("); addList(next); add(")"); } break; case Token.STRING: Preconditions.checkState(childCount == 0); add(jsString(n.getString(), outputCharsetEncoder)); break; case Token.DELPROP: Preconditions.checkState(childCount == 1); add("delete "); add(first); break; case Token.OBJECTLIT: { Preconditions.checkState(childCount % 2 == 0); boolean needsParens = (context == Context.START_OF_EXPR); if (needsParens) { add("("); } add("{"); for (Node c = first; c != null; c = c.getNext().getNext()) { if (c != first) { cc.listSeparator(); } // Object literal property names don't have to be quoted if they are // not JavaScript keywords if (c.getType() == Token.STRING && !TokenStream.isKeyword(c.getString()) && TokenStream.isJSIdentifier(c.getString()) && // do not encode literally any non-literal characters that were // unicode escaped. NodeUtil.isLatin(c.getString()))

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { add(c.getString()); } else { addExpr(c, 1); } add(":"); addExpr(c.getNext(), 1); } add("}"); if (needsParens) { add(")"); } break; } case Token.SWITCH: add("switch("); add(first); add(")"); cc.beginBlock(); addAllSiblings(first.getNext()); cc.endBlock(context == Context.STATEMENT); break; case Token.CASE: Preconditions.checkState(childCount == 2); add("case "); add(first); addCaseBody(last); break; case Token.DEFAULT: Preconditions.checkState(childCount == 1); add("default"); addCaseBody(first); break; case Token.LABEL: Preconditions.checkState(childCount == 2); add(first); add(":"); addNonEmptyExpression( last, getContextForNonEmptyExpression(context), true); break; // This node is auto generated in anonymous functions and should just get // ignored for our purposes. case Token.SETNAME: break; default: throw new Error("Unknown type " + type + "\n" + n.toStringTree()); } cc.endSourceMapping(n); } /** * Adds a block or expression, substituting a VOID with an empty statement. * This is used for "for (...);" and "if (...);" type statements. * * @param n The node to print. * @param context The context to determine how the node should be printed. */ private void addNonEmptyExpression( Node n, Context context, boolean allowNonBlockChild) { Node nodeToProcess = n; if (!allowNonBlockChild && n.getType() != Token.BLOCK) { if (validation) { throw new Error("Missing BLOCK child."); } } // Strip unneeded blocks, that is blocks with <2 children unless // the CodePrinter specifically wants to keep them. if (n.getType() == Token.BLOCK ) { int count = getNonEmptyChildCount(n); if (count == 0) { cc.endStatement(true); return;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> } if (count == 1) { // Hack around a couple of browser bugs: // Safari needs a block around function declarations. // IE6/7 needs a block around DOs. Node firstAndOnlyChild = getFirstNonEmptyChild(n); boolean alwaysWrapInBlock = cc.shouldPreserveExtraBlocks(); if (alwaysWrapInBlock || firstAndOnlyChild.getType() == Token.FUNCTION || firstAndOnlyChild.getType() == Token.DO) { cc.beginBlock(); add(firstAndOnlyChild, Context.STATEMENT); cc.maybeLineBreak(); cc.endBlock(context == Context.STATEMENT); return; } else { // Continue with the only child. nodeToProcess = firstAndOnlyChild; } } } if (nodeToProcess.getType() == Token.EMPTY) { cc.endStatement(true); } else { add(nodeToProcess, context); // VAR doesn't include ';' since it gets used in expressions - so any // VAR in a statement context needs a call to endStatement() here. if (nodeToProcess.getType() == Token.VAR) { cc.endStatement(); } } } /** * Adds a node at the left-hand side of an expression. Unlike * {@link #addExpr(Node,int)}, this preserves information about the context. * * The left side of an expression is special because in the JavaScript * grammar, certain tokens may be parsed differently when they are at * the beginning of a statement. For example, "{}" is parsed as a block, * but "{'x': 'y'}" is parsed as an object literal. */ void addLeftExpr(Node n, int minPrecedence, Context context) { addExpr(n, minPrecedence, context); } void addExpr(Node n, int minPrecedence) { addExpr(n, minPrecedence, Context.OTHER); } private void addExpr(Node n, int minPrecedence, Context context) { if ((NodeUtil.precedence(n.getType()) < minPrecedence) || ((context == Context.IN_FOR_INIT_CLAUSE) && (n.getType() == Token.IN))

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>){ add("("); add(n, clearContextForNoInOperator(context)); add(")"); } else { add(n, context); } } void addList(Node firstInList) { addList(firstInList, true, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument) { addList(firstInList, isArrayOrFunctionArgument, Context.OTHER); } void addList(Node firstInList, boolean isArrayOrFunctionArgument, Context lhsContext) { for (Node n = firstInList; n != null; n = n.getNext()) { boolean isFirst = n == firstInList; if (isFirst) { addLeftExpr(n, isArrayOrFunctionArgument ? 1 : 0, lhsContext); } else { cc.listSeparator(); addExpr(n, isArrayOrFunctionArgument ? 1 : 0); } } } /** * This function adds a comma-separated list as is specified by an ARRAYLIT * node with the associated skipIndexes array. This is a space optimization * since we avoid creating a whole Node object for each empty array literal * slot. * @param firstInList The first in the node list (chained through the next * property). * @param skipIndexes If not null, then the array of skipped entries in the * array. */ void addList(Node firstInList, int[] skipIndexes) { int nextSlot = 0; int nextSkipSlot = 0; for (Node n = firstInList; n != null; n = n.getNext()) { while (skipIndexes != null && nextSkipSlot < skipIndexes.length) { if (nextSlot == skipIndexes[nextSkipSlot]) { cc.listSeparator(); nextSlot++; nextSkipSlot++; } else { break; } } if (n != firstInList) { cc.listSeparator(); } addExpr(n, 1); nextSlot++; } } void addCaseBody(Node caseBody) { cc.beginCaseBody(); add(caseBody); cc.endCaseBody(); } void addAllSiblings(Node n) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> for (Node c = n; c != null; c = c.getNext()) { add(c); } } /** Outputs a js string, using the optimal (single/double) quote character */ static String jsString(String s, CharsetEncoder outputCharsetEncoder) { int singleq = 0, doubleq = 0; // could count the quotes and pick the optimal quote character for (int i = 0; i < s.length(); i++) { switch (s.charAt(i)) { case '"': doubleq++; break; case '\'': singleq++; break; } } String doublequote, singlequote; char quote; if (singleq < doubleq) { // more double quotes so escape the single quotes quote = '\''; doublequote = "\""; singlequote = "\\\'"; } else { // more single quotes so escape the doubles quote = '\"'; doublequote = "\\\""; singlequote = "\'"; } return strEscape(s, quote, doublequote, singlequote, "\\\\", outputCharsetEncoder); } /** Escapes regular expression */ static String regexpEscape(String s, CharsetEncoder outputCharsetEncoder) { return strEscape(s, '/', "\"", "'", "\\", outputCharsetEncoder); } /** * Escapes the given string to a double quoted (") JavaScript/JSON string */ static String escapeToDoubleQuotedJsString(String s) { return strEscape(s, '"', "\\\"", "\'", "\\\\", null); } /* If the user doesn't want to specify an output charset encoder, assume they want Latin/ASCII characters only. */ static String regexpEscape(String s) { return regexpEscape(s, null); } /** Helper to escape javascript string as well as regular expression */ static String strEscape(String s, char quote, String doublequoteEscape, String singlequoteEscape, String backslashEscape, CharsetEncoder outputCharsetEncoder) { StringBuilder sb = new StringBuilder(); sb.append(quote); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); switch (c) { case '\n': sb.append("\\n"); break; case

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> '\r': sb.append("\\r"); break; case '\t': sb.append("\\t"); break; case '\\': sb.append(backslashEscape); break; case '\"': sb.append(doublequoteEscape); break; case '\'': sb.append(singlequoteEscape); break; case '>': // Break --> into --\> or ]]> into ]]\> if (i >= 2 && ((s.charAt(i - 1) == '-' && s.charAt(i - 2) == '-') || (s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']'))) { sb.append("\\>"); } else { sb.append(c); } break; case '<': // Break </script into <\/script final String END_SCRIPT = "/script"; if (s.regionMatches(true, i + 1, END_SCRIPT, 0, END_SCRIPT.length())) { sb.append("<\\"); } else { sb.append(c); } break; default: // If we're given an outputCharsetEncoder, then check if the // character can be represented in this character set. if (outputCharsetEncoder != null) { if (outputCharsetEncoder.canEncode(c)) { sb.append(c); } else { // Unicode-escape the character. appendHexJavaScriptRepresentation(sb, c); } } else { // No charsetEncoder provided - pass straight latin characters // through, and escape the rest. Doing the explicit character // check is measurably faster than using the CharsetEncoder. if (c > 0x1f && c <= 0x7f) { sb.append(c); } else { // Other characters can be misinterpreted by some js parsers, // or perhaps mangled by proxies along the way, // so we play it safe and unicode escape them. appendHexJavaScriptRepresentation(sb, c); } } } } sb.append(quote); return sb.toString(); } static String identifierEscape(String s) { // First check if escaping is needed at all -- in most cases it isn't. if (NodeUtil

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>ertype of a record type * of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to * A and matches all constraints. Similarly, a defined type can be assigned * to a record type so long as that defined type matches all property * constraints of the record type. A record type of the form { a : A, b : B } * can be assigned to a record of type { a : A }. * * */ public class RecordType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private Map<String, JSType> properties = new HashMap<String, JSType>(); private boolean isFrozen = false; /** * Creates a record type. * * @param registry The type registry under which this type lives. * @param properties A map of all the properties of this record type. */ RecordType(JSTypeRegistry registry, Map<String, JSType> properties) { super(registry, null, null); for (String property : properties.keySet()) { defineDeclaredProperty(property, properties.get(property), false); } // Freeze the record type. isFrozen = true; } @Override public boolean equals(Object other) { if (!(other instanceof RecordType)) { return false; } // Compare properties. RecordType otherRecord = (RecordType) other; return otherRecord.properties.equals(properties); } @Override public ObjectType getImplicitPrototype() { return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE); } @Override boolean defineProperty(String propertyName, JSType type, boolean inferred, boolean inExterns) { if (isFrozen) { return false; } if (!inferred) { properties.put(propertyName, type); } return super.defineProperty(propertyName, type, inferred, inExterns); } @Override public JSType getLeastSupertype(JSType that) { if (!that.isRecordType()) { return super.getLeastSupertype(that); } RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The least supertype consist of those properties of the record

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> // type that both record types hold in common both by name and // type of the properties themselves. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && thatRecord.getPropertyType(property).equals( getPropertyType(property))) { builder.addProperty(property, getPropertyType(property)); } } return builder.build(); } @Override public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { RecordType thatRecord = (RecordType) that; RecordTypeBuilder builder = new RecordTypeBuilder(registry); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : properties.keySet()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).equals( getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property)); } for (String property : thatRecord.properties.keySet()) { if (!hasProperty(property)) { builder.addProperty(property, thatRecord.getPropertyType(property)); } } return builder.build(); } JSType greatestSubtype = super.getGreatestSubtype(that); if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union // of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the intersection of all of these unions. for (Map.Entry<String, JSType> entry : properties.entrySet()) { String propName = entry.getKey(); JSType propType = entry.getValue(); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getTypesWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>altPropType != null && !alt.equals(this) && alt.isSubtype(that) && (propType.isUnknownType() || altPropType.isUnknownType() || altPropType.equals(propType))) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; } @Override public boolean isRecordType() { return true; } @Override public boolean isSubtype(JSType that) { if (JSType.isSubtype(this, that)) { return true; } // Top of the record types is the empty record, or OBJECT_TYPE. if (registry.getNativeObjectType( JSTypeNative.OBJECT_TYPE).isSubtype(that)) { return true; } // A type is a subtype of a record type if it itself is a record // type and it has at least the same members as the parent record type // with the same types. if (!that.isRecordType()) { return false; } return RecordType.isSubtype(this, (RecordType) that); } /** Determines if typeA is a subtype of typeB */ static boolean isSubtype(ObjectType typeA, RecordType typeB) { // typeA is a subtype of record type typeB iff: // 1) typeA has all the properties declared in typeB. // 2) And for each property of typeB, // 2a) if the property of typeA is declared, it must be equal // to the type of the property of typeB, // 2b) otherwise, it must be a subtype of the property of typeB. // // To figure out why this is true, consider the following pseudo-code: // /** @type {{a: (Object,null)}} */ var x; // /** @type {{a: !Object}} */ var y; // var z = {a: {}}; // x.a = null; // // y cannot be assigned to x, because line 4 would violate y's declared // properties. But z can be assigned to x. Even though z and y are the // same type, the properties of z are inferred--

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>and so an assignment // to the property of z would not violate any restrictions on it. for (String property : typeB.properties.keySet()) { if (!typeA.hasProperty(property)) { return false; } JSType propA = typeA.getPropertyType(property); JSType propB = typeB.getPropertyType(property); if (!propA.isUnknownType() && !propB.isUnknownType()) { if (typeA.isPropertyTypeDeclared(property)) { if (!propA.equals(propB)) { return false; } } else { if (!propA.isSubtype(propB)) { return false; } } } } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("{ "); int i = 0; for (String property : properties.keySet()) { if (i > 0) { sb.append(", "); } sb.append(property); sb.append(" : "); sb.append(properties.get(property).toString()); ++i; } sb.append(" }"); return sb.toString(); } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { for (Map.Entry<String, JSType> entry : properties.entrySet()) { JSType type = entry.getValue(); JSType resolvedType = type.resolve(t, scope); if (type != resolvedType) { properties.put(entry.getKey(), resolvedType); } } return super.resolveInternal(t, scope); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Create an exception with the specified detail message. * * Errors internal to the JavaScript engine will simply throw a * RuntimeException. * * @param sourceName the name of the source reponsible for the error * @param lineNumber the line number of the source * @param columnNumber the columnNumber of the source (may be zero if * unknown) * @param lineSource the source of the line containing the error (may be * null if unknown) */ EcmaError(String errorName, String errorMessage, String sourceName, int lineNumber, String lineSource, int columnNumber) { recordErrorOrigin(sourceName, lineNumber, lineSource, columnNumber); this.errorName = errorName; this.errorMessage = errorMessage; } @Override public String details() { return errorName+": "+errorMessage; } /** * Gets the name of the error. * * ECMA edition 3 defines the following * errors: EvalError, RangeError, ReferenceError, * SyntaxError, TypeError, and URIError. Additional error names * may be added in the future. * * See ECMA edition 3, 15.11.7.9. * * @return the name of the error. */ public String getName() { return errorName; } /** * Gets the message corresponding to the error. * * See ECMA edition 3, 15.11.7.10. * * @return an implemenation-defined string describing the error. */ public String getErrorMessage() { return errorMessage; } /** * @deprecated Use {@link RhinoException#sourceName()} from the super class. */ @Deprecated public String getSourceName() { return sourceName(); } /** * @deprecated Use {@link RhinoException#lineNumber()} from the super class. */ @Deprecated public int getLineNumber() { return lineNumber(); } /** * @deprecated * Use {@link RhinoException#columnNumber()} from the super class. */ @Deprecated public int getColumnNumber() { return columnNumber(); } /** * @deprecated Use {@link RhinoException#

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> */ public class Scope implements StaticScope<JSType> { private final Map<String, Var> vars = new LinkedHashMap<String, Var>(); private final Scope parent; private final Node rootNode; /** The type of {@code this} in the current scope. */ private final ObjectType thisType; /** Whether this is a bottom scope for the purposes of type inference. */ private final boolean isBottom; /** Stores info about a variable */ public static class Var implements StaticSlot<JSType> { /** name */ String name; /** Var node */ Node nameNode; /** * The variable's type. */ private JSType type; /** * The variable's doc info. */ private JSDocInfo info = null; /** * Whether the variable's type has been inferred or is declared. An inferred * type may change over time (as more code is discovered), whereas a * declared type is a static contract that must be matched. */ private final boolean typeInferred; /** Input source */ CompilerInput input; /** Whether the variable is a define */ boolean isDefine; /** * The index at which the var is declared. e..g if it's 0, it's the first * declared variable in that scope */ int index; /** The enclosing scope */ Scope scope; /** * Creates a variable. * * @param inferred whether its type is inferred (as opposed to declared) */ private Var(boolean inferred) { this.typeInferred = inferred; } /** * Gets the name of the variable. */ public String getName() { return name; } /** * Gets the parent of the name node. */ public Node getParentNode() { return nameNode == null ? null : nameNode.getParent(); } /** * Gets the scope where this variable is declared. */ Scope getScope() { return scope; } /** * Returns the index within the scope stack. * e.g. function Foo(a) { var b; function c(d) { } } * a = 0, b = 1, c = 2, d = 3 */ int getLocalVarIndex() { int num = index; Scope

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> s = scope.getParent(); if (s == null) { throw new IllegalArgumentException("Var is not local"); } while (s.getParent() != null) { num += s.getVarCount(); s = s.getParent(); } return num; } /** * Returns whether this is a global variable. */ public boolean isGlobal() { return scope.isGlobal(); } /** * Returns whether this is a local variable. */ public boolean isLocal() { return scope.isLocal(); } /** * Returns whether this is defined in an extern file. */ boolean isExtern() { return input == null || input.isExtern(); } /** * Returns {@code true} if the variable is declared as a constant, * based on the value reported by {@code NodeUtil}. */ public boolean isConst() { return NodeUtil.isConstantName(nameNode); } /** * Returns {@code true} if the variable is declared as a define. * A variable is a define if it is annotaed by {@code @define}. */ public boolean isDefine() { return isDefine; } public Node getInitialValue() { Node parent = getParentNode(); return parent.getType() == Token.FUNCTION ? parent : nameNode.getFirstChild(); } /** * Gets this variable's type. To know whether this type has been inferred, * see {@code #isInferred()}. */ public JSType getType() { return type; } /** * Returns the name node that produced this variable. */ public Node getNameNode() { return nameNode; } /** * Gets the JSDocInfo for the variable. */ public JSDocInfo getJSDocInfo() { return info; } /** * Sets this variable's type. * @throws IllegalStateException if the variable's type is not inferred */ void setType(JSType type) { Preconditions.checkState(isTypeInferred()); this.type = type; } /** * Returns whether this variable's type is inferred. To get the variable's * type, see {@link #getType()}. */ public boolean isTypeInferred() { return typeInferred; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> public String getInputName() { if (input == null) return "<non-file>"; else return input.getName(); } public boolean isNoShadow() { if (info != null && info.isNoShadow()) { return true; } else { return false; } } @Override public boolean equals(Object other) { if (!(other instanceof Var)) { return false; } Var otherVar = (Var) other; return otherVar.nameNode == nameNode; } @Override public int hashCode() { return nameNode.hashCode(); } @Override public String toString() { return "Scope.Var " + name; } } /** * Creates a Scope given the parent Scope and the root node of the scope. * @param parent The parent Scope. Cannot be null. * @param rootNode Typically the FUNCTION node. */ Scope(Scope parent, Node rootNode) { Preconditions.checkNotNull(parent); Preconditions.checkArgument(rootNode != parent.rootNode); this.parent = parent; this.rootNode = rootNode; JSType nodeType = rootNode.getJSType(); if (nodeType != null && nodeType instanceof FunctionType) { thisType = ((FunctionType) nodeType).getTypeOfThis(); } else { thisType = parent.thisType; } this.isBottom = false; } /** * Creates a global Scope. * @param rootNode Typically the global BLOCK node. */ Scope(Node rootNode, AbstractCompiler compiler) { this.parent = null; this.rootNode = rootNode; thisType = compiler.getTypeRegistry().getNativeObjectType(GLOBAL_THIS); this.isBottom = false; } /** * Creates a empty Scope (bottom of the lattice). * @param rootNode Typically a FUNCTION node or the global BLOCK node. * @param thisType the type of {@code this} in this scope */ Scope(Node rootNode, ObjectType thisType) { this.parent = null; this.rootNode = rootNode; this.thisType = thisType; this.isBottom = true; } /** Whether this is the bottom of the lattice. */ boolean isBottom

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>() { return isBottom; } /** * Gets the container node of the scope. This is typically the FUNCTION * node or the global BLOCK/SCRIPT node. */ public Node getRootNode() { return rootNode; } public Scope getParent() { return parent; } Scope getGlobalScope() { Scope result = this; while (result.getParent() != null) { result = result.getParent(); } return result; } @Override public StaticScope<JSType> getParentScope() { return parent; } /** * Gets the type of {@code this} in the current scope. */ public ObjectType getTypeOfThis() { return thisType; } /** * Declares a variable whose type is inferred. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. */ Var declare(String name, Node nameNode, JSType type, CompilerInput input) { return declare(name, nameNode, type, input, true); } /** * Declares a variable. * * @param name name of the variable * @param nameNode the NAME node declaring the variable * @param type the variable's type * @param input the input in which this variable is defined. * @param inferred Whether this variable's type is inferred (as opposed * to declared). */ Var declare(String name, Node nameNode, JSType type, CompilerInput input, boolean inferred) { Preconditions.checkState(name != null && name.length() > 0); // Make sure that it's declared only once Preconditions.checkState(vars.get(name) == null); Var var = new Var(inferred); var.name = name; var.nameNode = nameNode; var.type = type; var.scope = this; var.index = vars.size(); var.input = input; // native variables do not have a name node. // TODO(user): make Var abstract and have NativeVar, NormalVar. JSDocInfo info = NodeUtil.getInfoForNameNode(nameNode); var

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.isDefine = info != null && info.isDefine(); var.info = info; vars.put(name, var); return var; } /** * Undeclares a variable, to be used when the compiler optimizes out * a variable and removes it from the scope. */ void undeclare(Var var) { Preconditions.checkState(var.scope == this); Preconditions.checkState(vars.get(var.name) == var); vars.remove(var.name); } public StaticSlot<JSType> getSlot(String name) { return getVar(name); } public StaticSlot<JSType> getOwnSlot(String name) { return vars.get(name); } /** * Returns the variable, may be null */ public Var getVar(String name) { Var var = vars.get(name); if (var != null) { return var; } else if (parent != null) { // Recurse up the parent Scope return parent.getVar(name); } else { return null; } } /** * Returns true if a variable is declared. */ public boolean isDeclared(String name, boolean recurse) { Scope scope = this; if (scope.vars.containsKey(name)) return true; if (scope.parent != null && recurse) { return scope.parent.isDeclared(name, recurse); } return false; } /** * Return an iterator over all of the variables declared in this scope. */ public Iterator<Var> getVars() { return vars.values().iterator(); } /** * Returns number of variables in this scope */ public int getVarCount() { return vars.size(); } /** * Returns whether this is the global scope. */ public boolean isGlobal() { return parent == null; } /** * Returns whether this is a local scope (i.e. not the global scope). */ public boolean isLocal() { return !isGlobal(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import java.io.Serializable; import java.util.Iterator; import java.util.List; import java.util.Set; /** * A builder for union types. * * @author nicksantos@google.com (Nick Santos) */ class UnionTypeBuilder implements Serializable { private static final long serialVersionUID = 1L; // If the best we can do is say "this object is one of twenty things", // then we should just give up and admit that we have no clue. private static final int MAX_UNION_SIZE = 20; private final JSTypeRegistry registry; private final List<JSType> alternates = Lists.newArrayList(); private boolean isAllType = false; private boolean isNativeUnknownType = false; private boolean areAllUnknownsChecked = true; // Memoize the result, in case build() is called multiple times. private JSType result = null; UnionTypeBuilder(JSTypeRegistry registry) { this.registry = registry; } /** * Adds an alternate to the union type under construction. Returns this * for easy chaining. */ UnionTypeBuilder addAlternate(JSType alternate) { // build() returns the bottom type by default, so we can // just bail out early here. if (alternate.isNoType()) { return this; } isAllType = isAllType || alternate.isAllType(); boolean isAlternateUnknown = alternate instanceof UnknownType; isNativeUnknownType = isNativeUnknownType || isAlternateUnknown; if (isAlternateUnknown) { areAllUnknownsChecked = areAllUnknownsChecked && alternate.isCheckedUnknownType(); } if (!isAllType && !isNativeUnknownType) { if (alternate instanceof UnionType) { UnionType union = (UnionType) alternate; for (JSType unionAlt : union.getAlternates()) { addAlternate(unionAlt); } } else { if (!alternate.isUnknownType()) { Iterator<JSType> it = alternates.iterator(); while

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (it.hasNext()) { JSType current = it.next(); if (!current.isUnknownType()) { if (alternate.isSubtype(current)) { // Alternate is unnecessary. return this; } else if (current.isSubtype(alternate)) { // Alternate makes current obsolete it.remove(); } } } } alternates.add(alternate); result = null; // invalidate the memoized result } } else { result = null; } return this; } /** * Creates a union. * @return A UnionType if it has two or more alternates, the * only alternate if it has one and otherwise {@code NO_TYPE}. */ JSType build() { if (result == null) { if (isAllType) { result = registry.getNativeType(ALL_TYPE); } else if (isNativeUnknownType) { if (areAllUnknownsChecked) { result = registry.getNativeType(CHECKED_UNKNOWN_TYPE); } else { result = registry.getNativeType(UNKNOWN_TYPE); } } else { Set<JSType> alternateSet = Sets.newUnmodifiableHashSet(alternates); int size = alternateSet.size(); if (size > MAX_UNION_SIZE) { result = registry.getNativeType(UNKNOWN_TYPE); } else { if (size > 1) { result = new UnionType(registry, alternateSet); } else if (size == 1) { result = alternates.iterator().next(); } else { result = registry.getNativeType(NO_TYPE); } } } } return result; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>. * <p> * @param key the key used to index the value * @param value the value to save */ public final void putThreadLocal(Object key, Object value) { if (sealed) onSealedMutation(); if (hashtable == null) hashtable = new Hashtable<Object, Object>(); hashtable.put(key, value); } /** * Remove values from thread-local storage. * @param key the key for the entry to remove. * @since 1.5 release 2 */ public final void removeThreadLocal(Object key) { if (sealed) onSealedMutation(); if (hashtable == null) return; hashtable.remove(key); } /** * @deprecated * @see #FEATURE_DYNAMIC_SCOPE * @see #hasFeature(int) */ @Deprecated public final boolean hasCompileFunctionsWithDynamicScope() { return compileFunctionsWithDynamicScopeFlag; } /** * @deprecated * @see #FEATURE_DYNAMIC_SCOPE * @see #hasFeature(int) */ @Deprecated public final void setCompileFunctionsWithDynamicScope(boolean flag) { if (sealed) onSealedMutation(); compileFunctionsWithDynamicScopeFlag = flag; } /** * Return the debugger context data associated with current context. * @return the debugger data, or null if debugger is not attached */ public final Object getDebuggerContextData() { return debuggerData; } /** * Implementation of {@link Context#hasFeature(int featureIndex)}. * This can be used to customize {@link Context} without introducing * additional subclasses. */ protected boolean hasFeature(int featureIndex) { int version; switch (featureIndex) { case Context.FEATURE_NON_ECMA_GET_YEAR: /* * During the great date rewrite of 1.3, we tried to track the * evolving ECMA standard, which then had a definition of * getYear which always subtracted 1900. Which we * implemented, not realizing that it was incompatible with * the old behavior... now, rather than thrash the behavior * yet again, we've decided to leave it with

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> /** * Check whether the name is in the list of names of objects * forcing the creation of activation objects. * * @param name the name of the object to test * * @return true if an function activation object is needed. */ public final boolean isActivationNeeded(String name) { return activationNames != null && activationNames.containsKey(name); } /** * Remove a name from the list of names forcing the creation of real * activation objects for functions. * * @param name the name of the object to remove from the list */ public void removeActivationName(String name) { if (sealed) onSealedMutation(); if (activationNames != null) activationNames.remove(name); } private static String implementationVersion; private boolean sealed; private Object sealKey; // for Objects, Arrays to tag themselves as being printed out, // so they don't print themselves out recursively. // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility ObjToIntMap iterating; Object interpreterSecurityDomain; int version; private ErrorReporter errorReporter; private Locale locale; private boolean generatingDebug; private boolean generatingDebugChanged; private boolean generatingSource=true; boolean compileFunctionsWithDynamicScopeFlag; boolean useDynamicScope; private Object debuggerData; private int enterCount; private int optimizationLevel; private Object propertyListeners; private Hashtable<Object, Object> hashtable; /** * This is the list of names of objects forcing the creation of * function activation records. */ Hashtable<Object, Object> activationNames; // For the interpreter to store the last frame for error reports etc. Object lastInterpreterFrame; // For the interpreter to store information about previous invocations // interpreter invocations ObjArray previousInterpreterInvocations; // For instruction counting (interpreter only) int instructionCount; int instructionThreshold; // It can be used to return the second index-like result from function int scratchIndex; // It can be used to return the second uint32 result from function long scratchUint32; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>BadModuleReference(name, ref); } } } } } private void reportBadModuleReference(Name name, Ref ref) { compiler.report( JSError.make(ref.sourceName, ref.node, STRICT_MODULE_DEP_QNAME, ref.module.getName(), name.declaration.module.getName(), name.fullName())); } private void reportRefToUndefinedName(Name name, Ref ref) { // grab the highest undefined ancestor to output in the warning message. while (name.parent != null && name.parent.globalSets + name.parent.localSets == 0) { name = name.parent; } // If this is an annotated EXPR-GET, don't do anything. Node parent = ref.node.getParent(); if (parent.getType() == Token.EXPR_RESULT) { JSDocInfo info = ref.node.getJSDocInfo(); if (info != null && info.hasTypedefType()) { return; } } compiler.report( JSError.make(ref.sourceName, ref.node, level, UNDEFINED_NAME_WARNING, name.fullName())); } /** * Checks whether the given name is a property, and whether that property * must be initialized with its full qualified name. */ private static boolean propertyMustBeInitializedByFullName(Name name) { // If an object literal in the global namespace is never aliased, // then all of its properties must be defined using its full qualified // name. This implies that its properties must all be in the global // namespace as well. // // The same is not true for FUNCTION and OTHER types, because their // implicit prototypes have properties that are not captured by the global // namespace. return name.parent != null && name.parent.aliasingGets == 0 && name.parent.type == Name.Type.OBJECTLIT; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> String name = callName.getString(); int dollarIndex = name.lastIndexOf('$'); if (dollarIndex != -1) { methodName = name.substring(dollarIndex + 1); } } if (methodName != null) { if (methodName.equals("inherits")) { return SubclassType.INHERITS; } else if (methodName.equals("mixin")) { return SubclassType.MIXIN; } } return null; } @Override public boolean isSuperClassReference(String propertyName) { return "superClass_".equals(propertyName); } /** * Given a qualified name node, strip "prototype" off the end. * * Examples of this transformation: * a.b.c => a.b.c * a.b.c.prototype => a.b.c */ private Node stripPrototype(Node qualifiedName) { if (qualifiedName.getType() == Token.GETPROP && qualifiedName.getLastChild().getString().equals("prototype")) { return qualifiedName.getFirstChild(); } return qualifiedName; } /** * Exctracts X from goog.provide('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfProvide(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.provide"); } /** * Exctracts X from goog.require('X'), if the applied Node is goog. * * @return The extracted class name, or null. */ @Override public String extractClassNameIfRequire(Node node, Node parent){ return extractClassNameIfGoog(node, parent, "goog.require"); } private static String extractClassNameIfGoog(Node node, Node parent, String functionName){ String className = null; if (NodeUtil.isExprCall(parent)) { Node callee = node.getFirstChild(); if (callee != null && callee.getType() == Token.GETPROP) { String qualifiedName = callee.getQualifiedName(); if ((functionName).equals(qualifiedName)) { className = callee.getNext().getString(); } } } return className; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> /** * Use closure's implementation. * @return closure's function name for exporting properties. */ @Override public String getExportPropertyFunction() { return "goog.exportProperty"; } /** * Use closure's implementation. * @return closure's function name for exporting symbols. */ @Override public String getExportSymbolFunction() { return "goog.exportSymbol"; } @Override public List<String> identifyTypeDeclarationCall(Node n) { Node callName = n.getFirstChild(); if ("goog.addDependency".equals(callName.getQualifiedName()) && n.getChildCount() >= 3) { Node typeArray = callName.getNext().getNext(); if (typeArray.getType() == Token.ARRAYLIT) { List<String> typeNames = Lists.newArrayList(); for (Node name = typeArray.getFirstChild(); name != null; name = name.getNext()) { if (name.getType() == Token.STRING) { typeNames.add(name.getString()); } } return typeNames; } } return null; } @Override public String identifyTypeDefAssign(Node n) { Node firstChild = n.getFirstChild(); int type = n.getType(); if (type == Token.ASSIGN) { if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) { return firstChild.getQualifiedName(); } } else if (type == Token.VAR && firstChild.hasChildren()) { if (TYPEDEF_NAME.equals( firstChild.getFirstChild().getQualifiedName())) { return firstChild.getString(); } } return null; } @Override public String getAbstractMethodName() { return "goog.abstractMethod"; } @Override public String getSingletonGetterClassName(Node callNode) { Node callName = callNode.getFirstChild(); if (!"goog.addSingletonGetter".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node classNode = callName.getNext(); if (!classNode.isQualifiedName()) { return null; } return callName.getNext().getQualifiedName(); } @Override public void applySingletonGetter(

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>FunctionType functionType, FunctionType getterType, ObjectType objectType) { functionType.defineDeclaredProperty("getInstance", getterType, false); functionType.defineDeclaredProperty("instance_", objectType, false); } @Override public String getGlobalObject() { return "goog.global"; } private final Set<String> propertyTestFunctions = ImmutableSet.of( "goog.isDef", "goog.isNull", "goog.isDefAndNotNull", "goog.isString", "goog.isNumber", "goog.isBoolean", "goog.isFunction", "goog.isArray", "goog.isObject"); @Override public boolean isPropertyTestFunction(Node call) { Preconditions.checkArgument(call.getType() == Token.CALL); return propertyTestFunctions.contains( call.getFirstChild().getQualifiedName()); } @Override public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t, Node callNode) { Preconditions.checkArgument(callNode.getType() == Token.CALL); Node callName = callNode.getFirstChild(); if (!"goog.reflect.object".equals(callName.getQualifiedName()) || callName.getChildCount() != 2) { return null; } Node typeNode = callName.getNext(); if (!typeNode.isQualifiedName()) { return null; } Node objectNode = typeNode.getNext(); if (objectNode.getType() != Token.OBJECTLIT) { t.getCompiler().report(JSError.make(t.getSourceName(), callNode, OBJECTLIT_EXPECTED)); return null; } return new ObjectLiteralCast(typeNode.getQualifiedName(), typeNode.getNext()); } /** * {@inheritDoc} */ @Override public boolean isOptionalParameter(Node parameter) { return false; } /** * {@inheritDoc} */ @Override public boolean isVarArgsParameter(Node parameter) { return false; } /** * {@inheritDoc} */ @Override public boolean isPrivate(String name) { return false; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> default: Kit.codeBug(); } return null; } private static class NumberNode extends Node { private static final long serialVersionUID = 1L; NumberNode(double number) { super(Token.NUMBER); this.number = number; } public NumberNode(double number, int lineno, int charno) { super(Token.NUMBER, lineno, charno); this.number = number; } @Override public double getDouble() { return this.number; } @Override public void setDouble(double d) { this.number = d; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof NumberNode && getDouble() == ((NumberNode) node).getDouble()); } private double number; } private static class StringNode extends Node { private static final long serialVersionUID = 1L; StringNode(int type, String str) { super(type); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } StringNode(int type, String str, int lineno, int charno) { super(type, lineno, charno); if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } /** returns the string content. * @return non null. */ @Override public String getString() { return this.str; } /** sets the string content. * @param str the new value. Non null. */ @Override public void setString(String str) { if (null == str) { throw new IllegalArgumentException("StringNode: str is null"); } this.str = str; } @Override public boolean isEquivalentTo(Node node) { return (node instanceof StringNode && this.str.equals(((StringNode) node).str)); } /** * If the property is not defined, this was not a quoted key. The * QUOTED_PROP int property is only assigned to STRING tokens used as * object lit keys. * @return true if this was a quoted string key in an object literal. */ @Override public boolean isQuotedString

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>() { return getBooleanProp(QUOTED_PROP); } /** * This should only be called for STRING nodes created in object lits. */ @Override public void setQuotedString() { putBooleanProp(QUOTED_PROP, true); } private String str; } private static class PropListItem implements Serializable { private static final long serialVersionUID = 1L; PropListItem next; int type; int intValue; Object objectValue; } public Node(int nodeType) { type = nodeType; parent = null; sourcePosition = -1; } public Node(int nodeType, Node child) { Preconditions.checkArgument(child.parent == null, "new child has existing parent"); Preconditions.checkArgument(child.next == null, "new child has existing sibling"); type = nodeType; parent = null; first = last = child; child.next = null; child.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node right) { Preconditions.checkArgument(left.parent == null, "first new child has existing parent"); Preconditions.checkArgument(left.next == null, "first new child has existing sibling"); Preconditions.checkArgument(right.parent == null, "second new child has existing parent"); Preconditions.checkArgument(right.next == null, "second new child has existing sibling"); type = nodeType; parent = null; first = left; last = right; left.next = right; left.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> = this; mid.next = right; mid.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, Node left, Node mid, Node mid2, Node right) { Preconditions.checkArgument(left.parent == null); Preconditions.checkArgument(left.next == null); Preconditions.checkArgument(mid.parent == null); Preconditions.checkArgument(mid.next == null); Preconditions.checkArgument(mid2.parent == null); Preconditions.checkArgument(mid2.next == null); Preconditions.checkArgument(right.parent == null); Preconditions.checkArgument(right.next == null); type = nodeType; parent = null; first = left; last = right; left.next = mid; left.parent = this; mid.next = mid2; mid.parent = this; mid2.next = right; mid2.parent = this; right.next = null; right.parent = this; sourcePosition = -1; } public Node(int nodeType, int lineno, int charno) { type = nodeType; parent = null; sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node child, int lineno, int charno) { this(nodeType, child); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node right, int lineno, int charno) { this(nodeType, left, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node right, int lineno, int charno) { this(nodeType, left, mid, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node left, Node mid, Node mid2, Node right, int lineno, int charno) { this(nodeType, left, mid, mid2, right); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children, int lineno,

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> int charno) { this(nodeType, children); sourcePosition = mergeLineCharNo(lineno, charno); } public Node(int nodeType, Node[] children) { this.type = nodeType; parent = null; if (children.length != 0) { this.first = children[0]; this.last = children[children.length - 1]; for (int i = 1; i < children.length; i++) { if (null != children[i - 1].next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } children[i - 1].next = children[i]; Preconditions.checkArgument(children[i - 1].parent == null); children[i - 1].parent = this; } Preconditions.checkArgument( children[children.length - 1].parent == null); children[children.length - 1].parent = this; if (null != this.last.next) { // fail early on loops. implies same node in array twice throw new IllegalArgumentException("duplicate child"); } } } public static Node newNumber(double number) { return new NumberNode(number); } public static Node newNumber(double number, int lineno, int charno) { return new NumberNode(number, lineno, charno); } public static Node newString(String str) { return new StringNode(Token.STRING, str); } public static Node newString(int type, String str) { return new StringNode(type, str); } public static Node newString(String str, int lineno, int charno) { return new StringNode(Token.STRING, str, lineno, charno); } public static Node newString(int type, String str, int lineno, int charno) { return new StringNode(type, str, lineno, charno); } public int getType() { return type; } public void setType(int type) { this.type = type; } public boolean hasChildren() { return first != null; } public Node getFirstChild() { return first; } public Node getLastChild

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>() { return last; } public Node getNext() { return next; } public Node getChildBefore(Node child) { if (child == first) return null; Node n = first; while (n.next != child) { n = n.next; if (n == null) throw new RuntimeException("node is not a child"); } return n; } public Node getChildAtIndex(int i) { Node n = first; while (i > 0) { n = n.next; i--; } return n; } public Node getLastSibling() { Node n = this; while (n.next != null) { n = n.next; } return n; } public void addChildToFront(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = first; first = child; if (last == null) { last = child; } } public void addChildToBack(Node child) { Preconditions.checkArgument(child.parent == null); Preconditions.checkArgument(child.next == null); child.parent = this; child.next = null; if (last == null) { first = last = child; return; } last.next = child; last = child; } public void addChildrenToFront(Node children) { for (Node child = children; child != null; child = child.next) { Preconditions.checkArgument(child.parent == null); child.parent = this; } Node lastSib = children.getLastSibling(); lastSib.next = first; first = children; if (last == null) { last = lastSib; } } public void addChildrenToBack(Node children) { for (Node child = children; child != null; child = child.next) { // Hmmm... IRFactory doesn't remove before calling this. Preconditions.checkArgument(child.parent == null); child.parent = this; } if (last != null) { last.next = children; }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> last = children.getLastSibling(); if (first == null) { first = children; } } /** * Add 'child' before 'node'. */ public void addChildBefore(Node newChild, Node node) { Preconditions.checkArgument(node != null, "The existing child node of the parent should not be null."); Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); if (first == node) { newChild.parent = this; newChild.next = first; first = newChild; return; } Node prev = getChildBefore(node); addChildAfter(newChild, prev); } /** * Add 'child' after 'node'. */ public void addChildAfter(Node newChild, Node node) { Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); newChild.parent = this; newChild.next = node.next; node.next = newChild; if (last == node) { last = newChild; } } /** * Detach a child from its parent and siblings. */ public void removeChild(Node child) { Node prev = getChildBefore(child); if (prev == null) first = first.next; else prev.next = child.next; if (child == last) last = prev; child.next = null; child.parent = null; } /** * Detaches child from Node and replaces it with newChild. */ public void replaceChild(Node child, Node newChild) { Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); // Copy over important information. newChild.copyInformationFrom(child); newChild.next = child.next; newChild.parent = this; if (child ==

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> first) { first = newChild; } else { Node prev = getChildBefore(child); prev.next = newChild; } if (child == last) last = newChild; child.next = null; child.parent = null; } public void replaceChildAfter(Node prevChild, Node newChild) { Preconditions.checkArgument(prevChild.parent == this, "prev is not a child of this node."); Preconditions.checkArgument(newChild.next == null, "The new child node has siblings."); Preconditions.checkArgument(newChild.parent == null, "The new child node already has a parent."); // Copy over important information. newChild.copyInformationFrom(prevChild); Node child = prevChild.next; newChild.next = child.next; newChild.parent = this; prevChild.next = newChild; if (child == last) last = newChild; child.next = null; child.parent = null; } private PropListItem lookupProperty(int propType) { PropListItem x = propListHead; while (x != null && propType != x.type) { x = x.next; } return x; } private PropListItem ensureProperty(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { item = new PropListItem(); item.type = propType; item.next = propListHead; propListHead = item; } return item; } public void removeProp(int propType) { PropListItem x = propListHead; if (x != null) { PropListItem prev = null; while (x.type != propType) { prev = x; x = x.next; if (x == null) { return; } } if (prev == null) { propListHead = x.next; } else { prev.next = x.next; } } } public Object getProp(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { return null; } return item.objectValue; } public

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> boolean getBooleanProp(int propType) { return getIntProp(propType, 0) != 0; } public int getIntProp(int propType, int defaultValue) { PropListItem item = lookupProperty(propType); if (item == null) { return defaultValue; } return item.intValue; } public int getExistingIntProp(int propType) { PropListItem item = lookupProperty(propType); if (item == null) { Kit.codeBug(); } return item.intValue; } public void putProp(int propType, Object prop) { if (prop == null) { removeProp(propType); } else { PropListItem item = ensureProperty(propType); item.objectValue = prop; } } public void putBooleanProp(int propType, boolean prop) { putIntProp(propType, prop ? 1 : 0); } public void putIntProp(int propType, int prop) { PropListItem item = ensureProperty(propType); item.intValue = prop; } // Gets all the property types, in sorted order. private int[] getSortedPropTypes() { int count = 0; for (PropListItem x = propListHead; x != null; x = x.next) { count++; } int[] keys = new int[count]; for (PropListItem x = propListHead; x != null; x = x.next) { count--; keys[count] = x.type; } Arrays.sort(keys); return keys; } public int getLineno() { return extractLineno(sourcePosition); } public int getCharno() { return extractCharno(sourcePosition); } /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */ public double getDouble() throws UnsupportedOperationException { if (this.getType() == Token.NUMBER) { throw new IllegalStateException( "Number node not created with Node.newNumber"); } else { throw new UnsupportedOperationException( this + " is not a number node"); } } /** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */ public void set

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> jsType.toString(); if (jsTypeString != null) { sb.append(" : "); sb.append(jsTypeString); } } } } } public String toStringTree() { return toStringTreeImpl(); } private String toStringTreeImpl() { try { StringBuffer s = new StringBuffer(); appendStringTree(s); return s.toString(); } catch (IOException e) { throw new RuntimeException("Should not happen\n" + e); } } public void appendStringTree(Appendable appendable) throws IOException { toStringTreeHelper(this, 0, appendable); } private static void toStringTreeHelper(Node n, int level, Appendable sb) throws IOException { if (Token.printTrees) { for (int i = 0; i != level; ++i) { sb.append(" "); } sb.append(n.toString()); sb.append('\n'); for (Node cursor = n.getFirstChild(); cursor != null; cursor = cursor.getNext()) { toStringTreeHelper(cursor, level + 1, sb); } } } int type; // type of the node; Token.NAME for example Node next; // next sibling private Node first; // first element of a linked list of children private Node last; // last element of a linked list of children /** * Linked list of properties. Since vast majority of nodes would have * no more then 2 properties, linked list saves memory and provides * fast lookup. If this does not holds, propListHead can be replaced * by UintMap. */ private PropListItem propListHead; /** * COLUMN_BITS represents how many of the lower-order bits of * sourcePosition are reserved for storing the column number. * Bits above these store the line number. * This gives us decent position information for everything except * files already passed through a minimizer, where lines might * be longer than 4096 characters. */ public static final int COLUMN_BITS = 12; /** * MAX_COLUMN_NUMBER represents the maximum column number that can * be represented. JSCompiler's modifications to Rhino cause all * tokens located beyond the maximum column to

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> else { return lineCharNo >>> COLUMN_BITS; } } /** * Extracts the character number and character number from a merged line * char number (see {@link #mergeLineCharNo(int, int)}). */ protected static int extractCharno(int lineCharNo) { if (lineCharNo == -1) { return -1; } else { return lineCharNo & COLUMN_MASK; } } //========================================================================== // Iteration /** * <p>Return an iterable object that iterates over this nodes's children. * The iterator does not support the optional operation * {@link Iterator#remove()}.</p> * * <p>To iterate over a node's siblings, one can write</p> * <pre>Node n = ...; * for (Node child : n.children()) { ...</pre> */ public Iterable<Node> children() { if (first == null) { return Collections.emptySet(); } else { return new SiblingNodeIterable(first); } } /** * <p>Return an iterable object that iterates over this nodes's siblings. * The iterator does not support the optional operation * {@link Iterator#remove()}.</p> * * <p>To iterate over a node's siblings, one can write</p> * <pre>Node n = ...; * for (Node sibling : n.siblings()) { ...</pre> */ public Iterable<Node> siblings() { return new SiblingNodeIterable(this); } /** * @see Node#siblings() */ private static final class SiblingNodeIterable implements Iterable<Node>, Iterator<Node> { private final Node start; private Node current; private boolean used; SiblingNodeIterable(Node start) { this.start = start; this.current = start; this.used = false; } public Iterator<Node> iterator() { if (!used) { used = true; return this; } else { // We have already used the current object as an iterator; // we must create a new SiblingNodeIterable based on this // iterable's start node. // // Since the primary use case for

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Node.children is in for // loops, this branch is extremely unlikely. return (new SiblingNodeIterable(start)).iterator(); } } public boolean hasNext() { return current != null; } public Node next() { if (current == null) { throw new NoSuchElementException(); } try { return current; } finally { current = current.getNext(); } } public void remove() { throw new UnsupportedOperationException(); } } //========================================================================== // Accessors public Node getParent() { return parent; } /** * Gets the ancestor node relative to this. * @param level 0 = this, 1 = the parent, etc. */ public Node getAncestor(int level) { Preconditions.checkArgument(level >= 0); Node node = this; while(node != null && level-- > 0) { node = node.getParent(); } return node; } /** * Iterates all of the node's ancestors excluding itself. */ public AncestorIterable getAncestors() { return new AncestorIterable(this.getParent()); } /** * Iterator to go up the ancestor tree. */ public static class AncestorIterable implements Iterable<Node> { private Node cur; /** * @param cur The node to start. */ AncestorIterable(Node cur) { this.cur = cur; } public Iterator<Node> iterator() { return new Iterator<Node>() { public boolean hasNext() { return cur != null; } public Node next() { if (!hasNext()) throw new NoSuchElementException(); Node n = cur; cur = cur.getParent(); return n; } public void remove() { throw new UnsupportedOperationException(); } }; } } /** * Check for one child more efficiently than by iterating over all the * children as is done with Node.getChildCount(). * @return Whether the node has exactly one child. */ public boolean hasOneChild() { return first != null && first == last; } /** * Check for more than one child more efficiently than by iterating over all * the children as is done with Node.getChildCount(). * @return Whether the node more than

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> one child. */ public boolean hasMoreThanOneChild() { return first != null && first != last; } public int getChildCount() { int c = 0; for (Node n = first; n != null; n = n.next) c++; return c; } // Intended for testing and verification only. public boolean hasChild(Node child) { for (Node n = first; n != null; n = n.getNext()) { if (child == n) { return true; } } return false; } /** * Checks if the subtree under this node is the same as another subtree. * Returns null if it's equal, or a message describing the differences. */ public String checkTreeEquals(Node node2) { NodeMismatch diff = checkTreeEqualsImpl(node2); if (diff != null) { return "Node tree inequality:" + "\nTree1:\n" + toStringTree() + "\n\nTree2:\n" + node2.toStringTree(); } return null; } /** * If this is a compilation pass and not a test, do not construct error * strings. Instead return true if the trees are equal. */ public boolean checkTreeEqualsSilent(Node node2) { return checkTreeEqualsImpl(node2) == null; } /** * Compare this node to node2 recursively and return the first pair * of nodes that differs doing a preorder depth-first traversal. * Package private for testing. Returns null if the nodes are equivalent. */ NodeMismatch checkTreeEqualsImpl(Node node2) { boolean eq = false; if (type == node2.getType() && getChildCount() == node2.getChildCount() && getClass() == node2.getClass()) { eq = this.isEquivalentTo(node2); } if (!eq) { return new NodeMismatch(this, node2); } NodeMismatch res = null; Node n, n2; for (n = first, n2 = node2.first; res == null && n != null; n = n.next, n2 = n2.next) { res = n.checkTreeEqualsImpl(n2

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>); if (res != null) { return res; } } return res; } /** * Checks if the subtree under this node is the same as another subtree * including types. Returns null if it's equal, or a message describing the * differences. */ public boolean checkTreeTypeAwareEqualsSilent(Node node2) { return checkTreeTypeAwareEqualsImpl(node2) == null; } /** * Compare this node to node2 recursively and return the first pair * of nodes that differs doing a preorder depth-first traversal. * Package private for testing. Returns null if the nodes are equivalent. */ NodeMismatch checkTreeTypeAwareEqualsImpl(Node node2) { boolean eq = false; if (type == node2.getType() && getChildCount() == node2.getChildCount() && getClass() == node2.getClass() && Objects.equal(jsType, node2.getJSType())) { eq = this.isEquivalentTo(node2); } if (!eq) { return new NodeMismatch(this, node2); } NodeMismatch res = null; Node n, n2; for (n = first, n2 = node2.first; res == null && n != null; n = n.next, n2 = n2.next) { res = n.checkTreeTypeAwareEqualsImpl(n2); if (res != null) { return res; } } return res; } public static String tokenToName(int token) { switch (token) { case Token.ERROR: return "error"; case Token.EOF: return "eof"; case Token.EOL: return "eol"; case Token.ENTERWITH: return "enterwith"; case Token.LEAVEWITH: return "leavewith"; case Token.RETURN: return "return"; case Token.GOTO: return "goto"; case Token.IFEQ: return "ifeq"; case Token.IFNE: return "ifne"; case Token.SETNAME: return "setname"; case Token.BITOR: return "bitor"; case Token.BITXOR: return "bitxor"; case Token.BIT

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> node.getIntProp(INCRDECR_PROP, 0); if (post1 != post2) return false; } else if (type == Token.STRING) { int quoted1 = this.getIntProp(QUOTED_PROP, 0); int quoted2 = node.getIntProp(QUOTED_PROP, 0); if (quoted1 != quoted2) return false; } return true; } public boolean hasSideEffects() { switch (type) { case Token.EXPR_VOID: case Token.COMMA: if (last != null) return last.hasSideEffects(); else return true; case Token.HOOK: if (first == null || first.next == null || first.next.next == null) Kit.codeBug(); return first.next.hasSideEffects() && first.next.next.hasSideEffects(); case Token.ERROR: // Avoid cascaded error messages case Token.EXPR_RESULT: case Token.ASSIGN: case Token.ASSIGN_ADD: case Token.ASSIGN_SUB: case Token.ASSIGN_MUL: case Token.ASSIGN_DIV: case Token.ASSIGN_MOD: case Token.ASSIGN_BITOR: case Token.ASSIGN_BITXOR: case Token.ASSIGN_BITAND: case Token.ASSIGN_LSH: case Token.ASSIGN_RSH: case Token.ASSIGN_URSH: case Token.ENTERWITH: case Token.LEAVEWITH: case Token.RETURN: case Token.GOTO: case Token.IFEQ: case Token.IFNE: case Token.NEW: case Token.DELPROP: case Token.SETNAME: case Token.SETPROP: case Token.SETELEM: case Token.CALL: case Token.THROW: case Token.RETHROW: case Token.SETVAR: case Token.CATCH_SCOPE: case Token.RETURN_RESULT: case Token.SET_REF: case Token.DEL_REF: case Token.REF_CALL: case Token.TRY: case Token.SEMI: case Token.INC: case Token.DEC: case Token.EXPORT: case Token.IMPORT: case Token.IF

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>scopedQualifiedName() { switch (getType()) { case Token.NAME: return true; case Token.GETPROP: return getFirstChild().isUnscopedQualifiedName(); default: return false; } } //========================================================================== // Mutators /** * Removes this node from its parent. Equivalent to: * node.getParent().removeChild(); */ public Node detachFromParent() { Preconditions.checkState(parent != null); parent.removeChild(this); return this; } /** * Removes the first child of Node. Equivalent to: * node.removeChild(node.getFirstChild()); * @return The removed Node. */ public Node removeFirstChild() { Node child = first; if (child != null) { removeChild(child); } return child; } /** * @return A Node that is the head of the list of children. */ public Node removeChildren() { Node children = first; for (Node child = first; child != null; child = child.getNext()) { child.parent = null; } first = null; last = null; return children; } /** * Removes all children from this node and isolates the children from each * other. */ public void detachChildren() { for (Node child = first; child != null; ) { Node nextChild = child.getNext(); child.parent = null; child.next = null; child = nextChild; } first = null; last = null; } public Node removeChildAfter(Node prev) { Preconditions.checkArgument(prev.parent == this, "prev is not a child of this node."); Preconditions.checkArgument(prev.next != null, "no next sibling."); Node child = prev.next; prev.next = child.next; if (child == last) last = prev; child.next = null; child.parent = null; return child; } /** * @return A detached clone of the Node, specifically excluding its * children. */ public Node cloneNode() { Node result; try { result = (Node) super.clone(); result.next = null;

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> result.first = null; result.last = null; result.parent = null; } catch (CloneNotSupportedException e) { throw new RuntimeException(e.getMessage()); } return result; } /** * @return A detached clone of the Node and all its children. */ public Node cloneTree() { Node result = cloneNode(); for (Node n2 = getFirstChild(); n2 != null; n2 = n2.getNext()) { Node n2clone = n2.cloneTree(); n2clone.parent = result; if (result.last != null) { result.last.next = n2clone; } if (result.first == null) { result.first = n2clone; } result.last = n2clone; } return result; } /** * Copies source file and name information from the other * node given to the current node. Used for maintaining * debug information across node append and remove operations. */ public void copyInformationFrom(Node other) { if (getProp(ORIGINALNAME_PROP) == null) { putProp(ORIGINALNAME_PROP, other.getProp(ORIGINALNAME_PROP)); } if (getProp(SOURCEFILE_PROP) == null) { putProp(SOURCEFILE_PROP, other.getProp(SOURCEFILE_PROP)); sourcePosition = other.sourcePosition; } } /** * Copies source file and name information from the other node to the * entire tree rooted at this node. */ public void copyInformationFromForTree(Node other) { copyInformationFrom(other); for (Node child = getFirstChild(); child != null; child = child.getNext()) { child.copyInformationFromForTree(other); } } //========================================================================== // Custom annotations public JSType getJSType() { return jsType; } public void setJSType(JSType jsType) { this.jsType = jsType; } public FileLevelJsDocBuilder getJsDocBuilderForNode() { return new FileLevelJsDocBuilder(); } /** * An inner class that provides back-door access to the license * property of the JSDocInfo

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>#NAME} nodes * used to define a {@link Token#FUNCTION}'s argument list. */ public void setOptionalArg(boolean optionalArg) { putBooleanProp(OPT_ARG_NAME, optionalArg); } /** * Returns whether this node is an optional argument node. This * method's return value is meaningful only on {@link Token#NAME} nodes * used to define a {@link Token#FUNCTION}'s argument list. */ public boolean isOptionalArg() { return getBooleanProp(OPT_ARG_NAME); } /** * Sets whether this is a synthetic block that should not be considered * a real source block. */ public void setIsSyntheticBlock(boolean val) { putBooleanProp(SYNTHETIC_BLOCK_PROP, val); } /** * Returns whether this is a synthetic block that should not be considered * a real source block. */ public boolean isSyntheticBlock() { return getBooleanProp(SYNTHETIC_BLOCK_PROP); } /** * Sets the ES5 directives on this node. */ public void setDirectives(Set<String> val) { putProp(DIRECTIVES, val); } /** * Returns the set of ES5 directives for this node. */ @SuppressWarnings("unchecked") public Set<String> getDirectives() { return (Set<String>) getProp(DIRECTIVES); } /** * Sets whether this is a synthetic block that should not be considered * a real source block. */ public void setWasEmptyNode(boolean val) { putBooleanProp(EMPTY_BLOCK, val); } /** * Returns whether this is a synthetic block that should not be considered * a real source block. */ public boolean wasEmptyNode() { return getBooleanProp(EMPTY_BLOCK); } /** * Marks this function or constructor call node as having no side effects. * This property is only meaningful for {@link Token#CALL} and * {@link Token#NEW} nodes. */ public void setIsNoSideEffectsCall() { Preconditions.checkArgument( getType() == Token.CALL || getType() == Token.NEW, "setIsNoSideEffectsCall only supports CALL and NEW nodes, got " + Token

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.name(getType())); putBooleanProp(NO_SIDE_EFFECTS_CALL, true); } /** * Returns true if this node is a function or constructor call that * has no side effects. */ public boolean isNoSideEffectsCall() { return getBooleanProp(NO_SIDE_EFFECTS_CALL); } /** * This should only be called for STRING nodes created in object lits. */ public boolean isQuotedString() { return false; } /** * This should only be called for STRING nodes created in object lits. */ public void setQuotedString() { Kit.codeBug(); } static class NodeMismatch { final Node nodeA; final Node nodeB; NodeMismatch(Node nodeA, Node nodeB) { this.nodeA = nodeA; this.nodeB = nodeB; } @Override public boolean equals(Object object) { if (object instanceof NodeMismatch) { NodeMismatch that = (NodeMismatch) object; return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB); } return false; } @Override public int hashCode() { return Objects.hashCode(nodeA, nodeB); } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Override public boolean isNullable() { return false; } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isUnknownType() || that.isSubtype( getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) { return UNKNOWN; } return FALSE; } @Override public boolean isNumberValueType() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesStringContext() { return true; } @Override public boolean matchesObjectContext() { // TODO(user): Revisit this for ES4, which is stricter. return true; } @Override public String toString() { return "number"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.BOTH; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNumberType(); } @Override public JSType autoboxesTo() { return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> constructor; InstanceObjectType(JSTypeRegistry registry, FunctionType constructor) { this(registry, constructor, false); } InstanceObjectType(JSTypeRegistry registry, FunctionType constructor, boolean isNativeType) { super(registry, null, null, isNativeType); Preconditions.checkNotNull(constructor); this.constructor = constructor; } @Override public String getReferenceName() { return getConstructor().getReferenceName(); } @Override public boolean hasReferenceName() { return getConstructor().hasReferenceName(); } @Override public ObjectType getImplicitPrototype() { return getConstructor().getPrototype(); } @Override public FunctionType getConstructor() { return constructor; } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { ObjectType proto = getImplicitPrototype(); if (proto != null && proto.hasOwnDeclaredProperty(name)) { return false; } return super.defineProperty(name, type, inferred, inExterns); } @Override public String toString() { return constructor.getReferenceName(); } @Override boolean isTheObjectType() { return getConstructor().isNative() && "Object".equals(getReferenceName()); } @Override public boolean isInstanceType() { return true; } @Override public boolean isArrayType() { return getConstructor().isNative() && "Array".equals(getReferenceName()); } @Override public boolean isStringObjectType() { return getConstructor().isNative() && "String".equals(getReferenceName()); } @Override public boolean isBooleanObjectType() { return getConstructor().isNative() && "Boolean".equals(getReferenceName()); } @Override public boolean isNumberObjectType() { return getConstructor().isNative() && "Number".equals(getReferenceName()); } @Override public boolean isDateType() { return getConstructor().isNative() && "Date".equals(getReferenceName()); } @Override public boolean isRegexpType() { return getConstructor().isNative() && "RegExp".equals(getReferenceName()); } @Override public boolean isNominalType() { return hasReferenceName(); } @Override public boolean equals(Object that) { if

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (this == that) { return true; } else if (that instanceof JSType && this.isNominalType()) { ObjectType thatObj = ObjectType.cast((JSType) that); if (thatObj != null && thatObj.isNominalType()) { return getReferenceName().equals(thatObj.getReferenceName()); } } return false; } /** * If this is equal to a NamedType object, its hashCode must be equal * to the hashCode of the NamedType object. */ @Override public int hashCode() { if (hasReferenceName()) { return getReferenceName().hashCode(); } else { return super.hashCode(); } } @Override public Iterable<ObjectType> getCtorImplementedInterfaces() { return getConstructor().getImplementedInterfaces(); } // The owner will always be a resolved type, so there's no need to set // the constructor in resolveInternal. // (it would lead to infinite loops if we did). // JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>WarningLevels(CompilerOptions options, List<String> diagnosticGroups, CheckLevel level) { for (String name : diagnosticGroups) { DiagnosticGroup group = forName(name); Preconditions.checkNotNull(group, "No warning class for name: " + name); options.setWarningLevel(group, level); } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>1L; NullType(JSTypeRegistry registry) { super(registry); } @Override public boolean isNullType() { return true; } @Override public boolean isNullable() { return true; } @Override public boolean matchesNumberContext() { return true; } @Override public boolean matchesObjectContext() { return false; } @Override public boolean matchesStringContext() { return true; } @Override public JSType restrictByNotNullOrUndefined() { return registry.getNativeType(JSTypeNative.NO_TYPE); } @Override public TernaryValue testForEquality(JSType that) { if (UNKNOWN.equals(super.testForEquality(that))) { return UNKNOWN; } if (that.isNullType() || that.isVoidType()) { return TRUE; } if (that.isUnknownType() || that.isNullable()) { return UNKNOWN; } return FALSE; } @Override public String toString() { return "null"; } @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { return BooleanLiteralSet.FALSE; } @Override public <T> T visit(Visitor<T> visitor) { return visitor.caseNullType(); } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> com.google.javascript.rhino.ScriptRuntime; import com.google.javascript.rhino.Token; import static com.google.javascript.rhino.jstype.JSTypeNative.ALL_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.ARRAY_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.NO_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.UNKNOWN_TYPE; import static com.google.javascript.rhino.jstype.JSTypeNative.VOID_TYPE; import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * The type registry is used to resolve named types. * * <p>This class is not thread-safe. * * */ public class JSTypeRegistry implements Serializable { private static final long serialVersionUID = 1L; // TODO(user): An instance of this class should be used during // compilation. We also want to make all types' constructors package private // and force usage of this registry instead. This will allow us to evolve the // types without being tied by an open API. private final transient ErrorReporter reporter; // We use an Array instead of an immutable list because this lookup needs // to be very fast. When it was an immutable list, we were spending 5% of // CPU time on bounds checking inside get(). private final JSType[] nativeTypes; private final Map<String, JSType> namesToTypes; // Set of namespaces in which types (or other namespaces) exist. private final Set<String> namespaces = new HashSet<String>(); // NOTE(nicksantos): This is a terrible terrible hack. When type expressions // are evaluated, we need to be able to decide whether that type name // resolves to a nullable type or a non-nullable type. Object types are // nullable, but enum types are not. // // Notice that it's not good enough to just declare enum types sooner. // For example, if we have

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> // /** @enum {MyObject} */ var MyEnum = ...; // we won't be to declare "MyEnum" without evaluating the expression // {MyObject}, and following those dependencies starts to lead us into // undecidable territory. Instead, we "pre-declare" enum types, // so that the expression resolver can decide whether a given name is // nullable or not. private final Set<String> enumTypeNames = new HashSet<String>(); // Types that have been "forward-declared." // If these types are not declared anywhere in the binary, we shouldn't // try to type-check them at all. private final Set<String> forwardDeclaredTypes = new HashSet<String>(); // A map of properties to the types on which those properties have been // declared. private final Map<String, Set<ObjectType>> typesIndexedByProperty = Maps.newHashMap(); // A map of properties to the greatest subtype on which those properties have // been declared. This is filled lazily from the types declared in // typesIndexedByProperty. private final Map<String, JSType> greatestSubtypeByProperty = Maps.newHashMap(); // A map from interface name to types that implement it. private final Multimap<String, FunctionType> interfaceToImplementors = HashMultimap.create(); // All the unresolved named types. private final Multimap<StaticScope<JSType>, NamedType> unresolvedNamedTypes = ArrayListMultimap.create(); // All the resolved named types. private final Multimap<StaticScope<JSType>, NamedType> resolvedNamedTypes = ArrayListMultimap.create(); // NamedType warns about unresolved types in the last generation. private boolean lastGeneration = true; // The template type name. private String templateTypeName; // The template type. private TemplateType templateType; /** * Constructs a new type registry populated with the built-in types. */ public JSTypeRegistry(ErrorReporter reporter) { this.reporter = reporter; nativeTypes = new JSType[JSTypeNative.values().length]; namesToTypes = new HashMap<String, JSType>(); resetForTypeCheck(); } /** * Reset to run the TypeCheck pass. */ public void resetForTypeCheck() { typesIndexedByProperty.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.VOID_TYPE)); register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined"); register(getNativeType(JSTypeNative.VOID_TYPE), "void"); register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function"); } private void register(JSType type) { register(type, type.toString()); } private void register(JSType type, String name) { namesToTypes.put(name, type); // Add all the namespaces in which this name lives. while (name.indexOf('.') > 0) { name = name.substring(0, name.lastIndexOf('.')); namespaces.add(name); } } private void registerNativeType(JSTypeNative typeId, JSType type) { nativeTypes[typeId.ordinal()] = type; } /** * Tells the type system that {@code owner} may have a property named * {@code propertyName}. This allows the registry to keep track of what * types a property is defined upon. * * This is NOT the same as saying that {@code owner} must have a property * named type. ObjectType#hasProperty attempts to minimize false positives * ("if we're not sure, then don't type check this property"). The type * registry, on the other hand, should attempt to minimize false negatives * ("if this property is assigned anywhere in the program, it must * show up in the type registry"). */ public void registerPropertyOnType(String propertyName, ObjectType owner) { Set<ObjectType> typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { typesIndexedByProperty.put(propertyName, typeSet = Sets.newHashSet()); } greatestSubtypeByProperty.remove(propertyName); typeSet.add(owner); } /** * Gets the greatest subtype of the {@code type} that has a property * {@code propertyName} defined on it. */ public JSType getGreatestSubtypeWithProperty( JSType type, String propertyName) { if (greatestSubtypeByProperty.containsKey(propertyName)) { return greatestSubtypeByProperty.get(propertyName) .getGreatestSubtype(type); } if (typesIndexedByProperty.containsKey(propertyName)) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> UnionTypeBuilder builder = new UnionTypeBuilder(this); for (JSType alt : typesIndexedByProperty.get(propertyName)) { builder.addAlternate(alt); } JSType built = builder.build(); greatestSubtypeByProperty.put(propertyName, built); return built.getGreatestSubtype(type); } return getNativeType(NO_TYPE); } /** * Returns whether the given property can possibly be set on the given type. */ public boolean canPropertyBeDefined(JSType type, String propertyName) { if (typesIndexedByProperty.containsKey(propertyName)) { for (JSType alt : typesIndexedByProperty.get(propertyName)) { if (alt.isSubtype(type) || type.isSubtype(alt)) { return true; } } } return false; } /** * Returns each type that has a property {@code propertyName} defined on it. */ public Set<ObjectType> getTypesWithProperty(String propertyName) { Set<ObjectType> typeSet = typesIndexedByProperty.get(propertyName); if (typeSet == null) { return Sets.newHashSet(getNativeObjectType(NO_TYPE)); } return typeSet; } /** * Increments the current generation. Clients must call this in order to * move to the next generation of type resolution, allowing types to attempt * resolution again. */ public void incrementGeneration() { for (NamedType type : resolvedNamedTypes.values()) { type.clearResolved(); } unresolvedNamedTypes.putAll(resolvedNamedTypes); resolvedNamedTypes.clear(); } boolean isLastGeneration() { return lastGeneration; } /** * Sets whether this is the last generation. In the last generation, * {@link NamedType} warns about unresolved types. */ public void setLastGeneration(boolean lastGeneration) { this.lastGeneration = lastGeneration; } /** * Tells the type system that {@code type} implements interface {@code * InterfaceInstance}. * {@code inter} must be an ObjectType for the instance of the interface as it * could be a named type and not yet have the constructor. */ void registerTypeImplementingInterface( FunctionType type, ObjectType interfaceInstance) { interface

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>ToImplementors.put(interfaceInstance.getReferenceName(), type); } /** * Returns a collection of types that directly implement {@code * interfaceInstance}. Subtypes of implementing types are not guaranteed to * be returned. {@code interfaceInstance} must be an ObjectType for the * instance of the interface. */ public Collection<FunctionType> getDirectImplementors( ObjectType interfaceInstance) { return interfaceToImplementors.get(interfaceInstance.getReferenceName()); } /** * Records declared type names. Given the limited scopes of JavaScript, all * named types are dumped in a common global scope. We may need to revise this * assumption in the future. * * @param name The name of the type to be recorded. * @param t The actual type being associated with the name. * @return True if this name is not already defined, false otherwise. */ public boolean declareType(String name, JSType t) { if (namesToTypes.containsKey(name)) { return false; } register(t, name); return true; } /** * Records a forward-declared type name. We will not emit errors if this * type name never resolves to anything. */ public void forwardDeclareType(String name) { forwardDeclaredTypes.add(name); } /** * Whether this is a forward-declared type name. */ public boolean isForwardDeclaredType(String name) { return forwardDeclaredTypes.contains(name); } /** Determines whether the given JS package exists. */ public boolean hasNamespace(String name) { return namespaces.contains(name); } /** * Looks up a type by name. * * @param jsTypeName The name string. * @return the corresponding JSType object or {@code null} it cannot be found */ public JSType getType(String jsTypeName) { // TODO(user): Push every local type name out of namesToTypes so that // NamedType#resolve is correct. if (jsTypeName.equals(templateTypeName)) { return templateType; } return namesToTypes.get(jsTypeName); } public JSType getNativeType(JSTypeNative typeId) { return nativeTypes[typeId.ordinal()]; } public ObjectType getNative

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> { return new FunctionType( this, null, null, createParameters(parameterTypes), returnType); } /** * Creates a function type. The last parameter type of the function is * considered a variable length argument. * * @param returnType the function's return type * @param parameterTypes the parameters' types */ public FunctionType createFunctionTypeWithVarArgs( JSType returnType, List<JSType> parameterTypes) { return new FunctionType( this, null, null, createParametersWithVarArgs(parameterTypes), returnType); } /** * Creates a function type. * * @param returnType the function's return type * @param parameterTypes the parameters' types */ public FunctionType createFunctionType( JSType returnType, List<JSType> parameterTypes) { return new FunctionType( this, null, null, createParameters(parameterTypes), returnType); } /** * Creates a function type. The last parameter type of the function is * considered a variable length argument. * * @param returnType the function's return type * @param parameterTypes the parameters' types */ public FunctionType createFunctionTypeWithVarArgs( JSType returnType, JSType... parameterTypes) { return new FunctionType( this, null, null, createParametersWithVarArgs(parameterTypes), returnType); } /** * Creates a function type which can act as a constructor. * * @param returnType the function's return type * @param parameterTypes the parameters' types */ public FunctionType createConstructorType( JSType returnType, JSType... parameterTypes) { return createConstructorType( null, null, createParameters(parameterTypes), returnType); } /** * Creates a function type which can act as a constructor. The last * parameter type of the constructor is considered a variable length argument. * * @param returnType the function's return type * @param parameterTypes the parameters' types */ public FunctionType createConstructorTypeWithVarArgs( JSType returnType, JSType... parameterTypes) { return createConstructorType( null, null, createParametersWithVarArgs(parameterTypes), returnType); } /** * Creates a function type in which {@code this} refers to an object instance. * * @param instanceType the

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> type of {@code this} * @param returnType the function's return type * @param parameterTypes the parameters' types */ public JSType createFunctionType(ObjectType instanceType, JSType returnType, List<JSType> parameterTypes) { return new FunctionType(this, null, null, createParameters(parameterTypes), returnType, instanceType); } /** * Creates a function type in which {@code this} refers to an object instance. * The last parameter type of the function is considered a variable length * argument. * * @param instanceType the type of {@code this} * @param returnType the function's return type * @param parameterTypes the parameters' types */ public JSType createFunctionTypeWithVarArgs(ObjectType instanceType, JSType returnType, List<JSType> parameterTypes) { return new FunctionType(this, null, null, createParametersWithVarArgs(parameterTypes), returnType, instanceType); } /** * Creates a tree hierarchy representing a typed argument list. * * @param parameterTypes the parameter types. * @return a tree hierarchy representing a typed argument list. */ public Node createParameters(List<JSType> parameterTypes) { return createParameters( parameterTypes.toArray(new JSType[parameterTypes.size()])); } /** * Creates a tree hierarchy representing a typed argument list. The last * parameter type is considered a variable length argument. * * @param parameterTypes the parameter types. The last element of this array * is considered a variable length argument. * @return a tree hierarchy representing a typed argument list. */ public Node createParametersWithVarArgs(List<JSType> parameterTypes) { return createParametersWithVarArgs( parameterTypes.toArray(new JSType[parameterTypes.size()])); } /** * Creates a tree hierarchy representing a typed argument list. * * @param parameterTypes the parameter types. * @return a tree hierarchy representing a typed argument list. */ public Node createParameters(JSType... parameterTypes) { return createParameters(false, parameterTypes); } /** * Creates a tree hierarchy representing a typed argument list. The last * parameter type is considered a variable length argument. * * @param parameterTypes the parameter types.

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> true, false); } /** * Creates an interface function type. * @param name the function's name * @param source the node defining this function. Its type * ({@link Node#getType()}) must be {@link Token#FUNCTION}. */ public FunctionType createInterfaceType(String name, Node source) { return new FunctionType(this, name, source); } /** * Creates a parameterized type. */ public ParameterizedType createParameterizedType( ObjectType objectType, JSType parameterType) { return new ParameterizedType(this, objectType, parameterType); } /** * Identifies the name of an enum before we actually declare it. */ public void identifyEnumName(String name) { enumTypeNames.add(name); } /** * Creates a RecordType from the nodes representing said record type. * @param n The node with type info. * @param sourceName The source file name. * @param scope A scope for doing type name lookups. */ public JSType createRecordTypeFromNodes(Node n, String sourceName, StaticScope<JSType> scope) { RecordTypeBuilder builder = new RecordTypeBuilder(this); // For each of the fields in the record type. for (Node fieldTypeNode = n.getFirstChild(); fieldTypeNode != null; fieldTypeNode = fieldTypeNode.getNext()) { // Get the property's name. Node fieldNameNode = fieldTypeNode; boolean hasType = false; if (fieldTypeNode.getType() == Token.COLON) { fieldNameNode = fieldTypeNode.getFirstChild(); hasType = true; } String fieldName = fieldNameNode.getString(); // TODO(user): Move this into the lexer/parser. // Remove the string literal characters around a field name, // if any. if (fieldName.startsWith("'") || fieldName.startsWith("\"")) { fieldName = fieldName.substring(1, fieldName.length() - 1); } // Get the property's type. JSType fieldType = null; if (hasType) { // We have a declared type. fieldType = createFromTypeNodes( fieldTypeNode.getLastChild(), sourceName, scope); } else { // Otherwise, the type is UNKNOWN. fieldType =

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> instanceof ObjectType) && !(enumTypeNames.contains(n.getString()))) { Node typeList = n.getFirstChild(); if (typeList != null && ("Array".equals(n.getString()) || "Object".equals(n.getString()))) { JSType parameterType = createFromTypeNodes( typeList.getLastChild(), sourceName, scope); namedType = new ParameterizedType( this, (ObjectType) namedType, parameterType); if (typeList.hasMoreThanOneChild()) { JSType indexType = createFromTypeNodes( typeList.getFirstChild(), sourceName, scope); namedType = new IndexedType( this, (ObjectType) namedType, indexType); } } return createNullableType(namedType); } else { return namedType; } case Token.FUNCTION: ObjectType thisType = null; Node current = n.getFirstChild(); if (current.getType() == Token.THIS) { Node thisNode = current.getFirstChild(); thisType = ObjectType.cast( createFromTypeNodes(thisNode, sourceName, scope) .restrictByNotNullOrUndefined()); if (thisType == null) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.thisnotobject"), sourceName, thisNode.getLineno(), "", thisNode.getCharno()); } current = current.getNext(); } FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this); if (current.getType() == Token.LP) { Node args = current.getFirstChild(); for (Node arg = current.getFirstChild(); arg != null; arg = arg.getNext()) { if (arg.getType() == Token.ELLIPSIS) { if (arg.getChildCount() == 0) { paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE)); } else { paramBuilder.addVarArgs( createFromTypeNodes( arg.getFirstChild(), sourceName, scope)); } } else { JSType type = createFromTypeNodes(arg, sourceName, scope); if (arg.getType() == Token.EQUALS) { boolean addSuccess = paramBuilder.addOptionalParams(type); if (!addSuccess

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>) { reporter.warning( ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"), sourceName, arg.getLineno(), "", arg.getCharno()); } } else { paramBuilder.addRequiredParams(type); } } } current = current.getNext(); } JSType returnType = createFromTypeNodes(current, sourceName, scope); return new FunctionType(this, null, null, paramBuilder.build(), returnType, thisType, null); } throw new IllegalStateException( "Unexpected node in type expression: " + n.toString()); } /** * Sets the template type name. */ public void setTemplateTypeName(String name) { templateTypeName = name; templateType = new TemplateType(this, name); } /** * Clears the template type name. */ public void clearTemplateTypeName() { templateTypeName = null; templateType = null; } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>; } public boolean isCheckedUnknownType() { return false; } public boolean isUnionType() { return false; } public boolean isFunctionType() { return false; } public boolean isEnumElementType() { return false; } public boolean isEnumType() { return false; } public boolean isNamedType() { return false; } public boolean isRecordType() { return false; } public boolean isTemplateType() { return false; } /** * Tests whether this type is an {@code Object}, or any subtype thereof. * @return {@code this &lt;: Object} */ public boolean isObject() { return false; } /** * Whether this type is a {@link FunctionType} that is a constructor or a * named type that points to such a type. */ public boolean isConstructor() { return false; } /** * Whether this type is a nominal type (a named instance object or * a named enum). */ public boolean isNominalType() { return false; } /** * Whether this type is an Instance object of some constructor. */ public boolean isInstanceType() { return false; } /** * Whether this type is a {@link FunctionType} that is an interface or a named * type that points to such a type. */ public boolean isInterface() { return false; } /** * Whether this type is a {@link FunctionType} that is an ordinary function or * a named type that points to such a type. */ public boolean isOrdinaryFunction() { return false; } /** * This method relies on the fact that for the base {@link JSType}, only one * instance of each sub-type will ever be created in a given registry, so * there is no need to verify members. If the object pointers are not * identical, then the type member must be different. */ @Override public boolean equals(Object jsType) { if (jsType instanceof ProxyObjectType) { return jsType.equals(this); } return this == jsType; } @Override public int hashCode() { return System.identityHashCode(this); } /** * This

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> mean compatible types that do not lead * to step 22 of the definition of the Abstract Equality Comparison * Algorithm (11.9.3, page 55&ndash;56) of the ECMA-262 specification.<p> */ public final boolean canTestForEqualityWith(JSType that) { return this.testForEquality(that).equals(UNKNOWN); } /** * Compares {@code this} and {@code that}. * @return <ul> * <li>{@link TernaryValue#TRUE} if the comparison of values of * {@code this} type and {@code that} always succeed (such as * {@code undefined} compared to {@code null})</li> * <li>{@link TernaryValue#FALSE} if the comparison of values of * {@code this} type and {@code that} always fails (such as * {@code undefined} compared to {@code number})</li> * <li>{@link TernaryValue#UNKNOWN} if the comparison can succeed or * fail depending on the concrete values</li> * </ul> */ public TernaryValue testForEquality(JSType that) { if (that.isAllType() || that.isNoType() || that.isUnknownType()) { return UNKNOWN; } if (that.isEnumElementType()) { return that.testForEquality(this); } if (that instanceof UnionType) { UnionType union = (UnionType) that; TernaryValue result = null; for (JSType t : union.alternates) { TernaryValue test = this.testForEquality(t); if (result == null) { result = test; } else if (!result.equals(test)) { return UNKNOWN; } } } return null; } /** * Tests whether {@code this} and {@code that} are meaningfully * comparable using shallow comparison. By meaningfully, we mean compatible * types that are not rejected by step 1 of the definition of the Strict * Equality Comparison Algorithm (11.9.6, page 56&ndash;57) of the * ECMA-262 specification.<p> */ public final boolean can

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> &#8743; Object} = {@code Number}</li> * </ul> * @return {@code this &#8744; that} */ public JSType getGreatestSubtype(JSType that) { if (that.isRecordType()) { // Record types have their own implementation of getGreatestSubtype. return that.getGreatestSubtype(this); } return getGreatestSubtype(this, that); } /** * A generic implementation meant to be used as a helper for common * getGreatestSubtype implementations. */ static JSType getGreatestSubtype(JSType thisType, JSType thatType) { if (thatType.isEmptyType() || thatType.isAllType()) { // Defer to the implementations of the end lattice elements when // possible. return thatType.getGreatestSubtype(thisType); } else if (thisType.isUnknownType() || thatType.isUnknownType()) { // The greatest subtype with any unknown type is the universal // unknown type, unless the two types are equal. return thisType.equals(thatType) ? thisType : thisType.getNativeType(JSTypeNative.UNKNOWN_TYPE); } else if (thisType.isSubtype(thatType)) { return thisType; } else if (thatType.isSubtype(thisType)) { return thatType; } else if (thisType.isUnionType()) { return ((UnionType) thisType).meet(thatType); } else if (thatType.isUnionType()) { return ((UnionType) thatType).meet(thisType); } else if (thisType.isObject() && thatType.isObject()) { return thisType.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return thisType.getNativeType(JSTypeNative.NO_TYPE); } /** * Computes the restricted type of this type knowing that the * {@code ToBoolean} predicate has a specific value. For more information * about the {@code ToBoolean} predicate, see * {@link #getPossibleToBooleanOutcomes}. * * @param outcome the value of the {@code ToBoolean} predicate * * @return the restricted type, or the Any Type if the underlying

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> type could * not have yielded this ToBoolean value * * TODO(user): Move this method to the SemanticRAI and use the visit * method of types to get the restricted type. */ public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { BooleanLiteralSet literals = getPossibleToBooleanOutcomes(); if (literals.contains(outcome)) { return this; } else { return getNativeType(JSTypeNative.NO_TYPE); } } /** * Computes the set of possible outcomes of the {@code ToBoolean} predicate * for this type. The {@code ToBoolean} predicate is defined by the ECMA-262 * standard, 3<sup>rd</sup> edition. Its behavior for simple types can be * summarized by the following table: * <table> * <tr><th>type</th><th>result</th></tr> * <tr><td>{@code undefined}</td><td>{false}</td></tr> * <tr><td>{@code null}</td><td>{false}</td></tr> * <tr><td>{@code boolean}</td><td>{true, false}</td></tr> * <tr><td>{@code number}</td><td>{true, false}</td></tr> * <tr><td>{@code string}</td><td>{true, false}</td></tr> * <tr><td>{@code Object}</td><td>{true}</td></tr> * </table> * @return the set of boolean literals for this type */ public abstract BooleanLiteralSet getPossibleToBooleanOutcomes(); /** * Computes the subset of {@code this} and {@code that} types if equality * is observed. If a value {@code v1} of type {@code null} is equal to a value * {@code v2} of type {@code (undefined,number)}, we can infer that the * type of {@code v1} is {@code null} and the type of {@code v2} is * {@code undefined}. * * @return a pair containing the restricted type of {@code this} as the first * component and the restricted type of {@code that} as the second * element. The returned pair is never {@code null}

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> union type's constituents are a subtype of U. Formally<br> * {@code (T<sub>1</sub>, &hellip;, T<sub>n</sub>) &lt;: U} if and only * {@code T<sub>k</sub> &lt;: U} for all {@code k &isin; 1..n}.</li> * <li>(union-r) &mdash; A type U is a subtype of a union type if it is a * subtype of one of the union type's constituents. Formally<br> * {@code U &lt;: (T<sub>1</sub>, &hellip;, T<sub>n</sub>)} if and only * if {@code U &lt;: T<sub>k</sub>} for some index {@code k}.</li> * <li>(objects) &mdash; an Object {@code O<sub>1</sub>} is a subtype * of an object {@code O<sub>2</sub>} if it has more properties * than {@code O<sub>2</sub>} and all common properties are * pairwise subtypes.</li> * </ul> * * @return {@code this &lt;: that} */ public abstract boolean isSubtype(JSType that); /** * Whether this type is meaningfully different from {@code that} type. * This is a trickier check than pure equality, because it has to properly * handle unknown types. * * @see <a href="http://www.youtube.com/watch?v=_RpSv3HjpEw">Unknown * unknowns</a> */ public boolean differsFrom(JSType that) { // if there are no unknowns, just use normal equality. if (!this.isUnknownType() && !that.isUnknownType()) { return !this.equals(that); } // otherwise, they're different iff one is unknown and the other is not. return this.isUnknownType() ^ that.isUnknownType(); } /** * A generic implementation meant to be used as a helper for common subtyping * cases. */ static boolean isSubtype(JSType thisType, JSType thatType) { // unknown if

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> (thatType.isUnknownType()) { return true; } // equality if (thisType.equals(thatType)) { return true; } // all type if (thatType.isAllType()) { return true; } // unions if (thatType instanceof UnionType) { UnionType union = (UnionType)thatType; for (JSType element : union.alternates) { if (thisType.isSubtype(element)) { return true; } } } // named types if (thatType instanceof NamedType) { return thisType.isSubtype(((NamedType)thatType).referencedType); } return false; } /** * Visit this type with the given visitor. * @see com.google.javascript.rhino.jstype.Visitor * @return the value returned by the visitor */ public abstract <T> T visit(Visitor<T> visitor); /** * Resolve this type in the given scope. * * The returned value must be equal to {@code this}, as defined by * {@link Object#equals}. It may or may not be the same object. This method * may modify the internal state of {@code this}, as long as it does * so in a way that preserves Object equality. * * For efficiency, we should only resolve a type once per compilation job. * For incremental compilations, one compilation job may need the * artifacts from a previous generation, so we will eventually need * a generational flag instead of a boolean one. */ public final JSType resolve(ErrorReporter t, StaticScope<JSType> scope) { if (resolved) { // TODO(nicksantos): Check to see if resolve() looped back on itself. // Preconditions.checkNotNull(resolveResult); if (resolveResult == null) { return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE); } return resolveResult; } resolved = true; resolveResult = resolveInternal(t, scope); return resolveResult; } /** * @see #resolve */ abstract JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope); void setResolvedTypeInternal(JSType type) { resolveResult = type

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>Param = null; } } // Right now, the parser's type system doesn't have a good way // to model optional arguments. // // Suppose we have // function f(number, number) {} // function g(number) {} // If the second arg of f is optional, then f is a subtype of g, // but g is not a subtype of f. // If the second arg of f is required, then g is a subtype of f, // but f is not a subtype of g. // // Until we model optional params, let's just punt on this. // If one type has more arguments than the other, we won't check them. // // NOTE(nicksantos): This is described in Draft 2 of the ES4 spec, // Section 3.4.6: Subtyping Function Types. It seems really // strange but I haven't thought a lot about the implementation. } return true; } @Override public boolean equals(Object object) { // Please keep this method in sync with the hashCode() method below. if (!(object instanceof ArrowType)) { return false; } ArrowType that = (ArrowType) object; // if both return types are specified, then they should be equal if (returnType == null) { if (that.returnType != null) { return false; } } else { if (that.returnType == null) { return false; } if (!returnType.equals(that.returnType)) { return false; } } // if both types include parameters, the lists should be the same if (parameters == null) { return that.parameters == null; } else if (that.parameters == null) { return false; } Node thisParam = parameters.getFirstChild(); Node otherParam = that.parameters.getFirstChild(); while (thisParam != null && otherParam != null) { JSType thisParamType = thisParam.getJSType(); JSType otherParamType = otherParam.getJSType(); if (thisParamType != null) { // Both parameter lists give a type for this param, it should be equal if (otherParamType != null && !thisParamType.equals(otherParamType)) {

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> code will only run checks and not optimizations. */ abstract protected List<PassFactory> getChecks(); /** * Gets the optimization passes to run. * * Optimization passes revolve around producing smaller and faster code. * They should always run after checking passes. */ abstract protected List<PassFactory> getOptimizations(); /** * Gets a graph of the passes run. For debugging. */ GraphvizGraph getPassGraph() { LinkedDirectedGraph<String, String> graph = LinkedDirectedGraph.create(); Iterable<PassFactory> allPasses = Iterables.concat(getChecks(), getOptimizations()); String lastPass = null; String loopStart = null; for (PassFactory pass : allPasses) { String passName = pass.getName(); int i = 1; while (graph.hasNode(passName)) { passName = pass.getName() + (i++); } graph.createNode(passName); if (loopStart == null && !pass.isOneTimePass()) { loopStart = passName; } else if (loopStart != null && pass.isOneTimePass()) { graph.connect(lastPass, "loop", loopStart); loopStart = null; } if (lastPass != null) { graph.connect(lastPass, "", passName); } lastPass = passName; } return graph; } /** * Create a type inference pass. */ final TypeInferencePass makeTypeInference(AbstractCompiler compiler) { return new TypeInferencePass( compiler, compiler.getReverseAbstractInterpreter(), topScope, typedScopeCreator); } /** * Create a type-checking pass. */ final TypeCheck makeTypeCheck(AbstractCompiler compiler) { return new TypeCheck( compiler, compiler.getReverseAbstractInterpreter(), compiler.getTypeRegistry(), topScope, typedScopeCreator, options.reportMissingOverride, options.reportUnknownTypes) .reportMissingProperties(options.enables( DiagnosticGroup.forType(TypeCheck.INEXISTENT_PROPERTY))); } final static void addPassFactoryBefore( List<PassFactory> factoryList, PassFactory factory, String passName) { for (int i = 0; i

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> < factoryList.size(); i++) { if (factoryList.get(i).getName().equals(passName)) { factoryList.add(i, factory); return; } } throw new IllegalArgumentException( "No factory named '" + passName + "' in the factory list"); } /** * Find the first pass provider that does not have a delegate. */ final PassConfig getBasePassConfig() { PassConfig current = this; while (current instanceof PassConfigDelegate) { current = ((PassConfigDelegate) current).delegate; } return current; } /** * Get intermediate state for a running pass config, so it can * be paused and started again later. */ abstract State getIntermediateState(); /** * Set the intermediate state for a pass config, to restart * a compilation process that had been previously paused. */ abstract void setIntermediateState(State state); /** * An implementation of PassConfig that just proxies all its method calls * into an inner class. */ static class PassConfigDelegate extends PassConfig { private final PassConfig delegate; PassConfigDelegate(PassConfig delegate) { super(delegate.options); this.delegate = delegate; } @Override protected List<PassFactory> getChecks() { return delegate.getChecks(); } @Override protected List<PassFactory> getOptimizations() { return delegate.getOptimizations(); } @Override ScopeCreator getScopeCreator() { return delegate.getScopeCreator(); } @Override Scope getTopScope() { return delegate.getTopScope(); } @Override State getIntermediateState() { return delegate.getIntermediateState(); } @Override void setIntermediateState(State state) { delegate.setIntermediateState(state); } } /** * Intermediate state for a running pass configuration. */ static class State implements Serializable { private static final long serialVersionUID = 1L; final Map<String, Integer> cssNames; final Set<String> exportedNames; final CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator; final VariableMap variableMap; final VariableMap propertyMap; final VariableMap anonymousFunctionNameMap; final FunctionNames functionNames; State(Map<String, Integer> cssNames,

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> Set<String> exportedNames, CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator, VariableMap variableMap, VariableMap propertyMap, VariableMap anonymousFunctionNameMap, FunctionNames functionNames) { this.cssNames = cssNames; this.exportedNames = exportedNames; this.crossModuleIdGenerator = crossModuleIdGenerator; this.variableMap = variableMap; this.propertyMap = propertyMap; this.anonymousFunctionNameMap = anonymousFunctionNameMap; this.functionNames = functionNames; } } }

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>import com.google.common.collect.Sets; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import java.util.Collections; import java.util.List; import java.util.Set; /** * This derived type provides extended information about a function, including * its return type and argument types.<p> * * Note: the parameters list is the LP node that is the parent of the * actual NAME node containing the parsed argument list (annotated with * JSDOC_TYPE_PROP's for the compile-time type of each argument. * * */ public class FunctionType extends PrototypeObjectType { private static final long serialVersionUID = 1L; private enum Kind { ORDINARY, CONSTRUCTOR, INTERFACE } /** * {@code [[Call]]} property. */ private ArrowType call; /** * The {@code prototype} property. This field is lazily initialized by * {@code #getPrototype()}. The most important reason for lazily * initializing this field is that there are cycles in the native types * graph, so some prototypes must temporarily be {@code null} during * the construction of the graph. */ private FunctionPrototypeType prototype; /** * Whether a function is a constructor, an interface, or just an ordinary * function. */ private final Kind kind; /** * The type of {@code this} in the scope of this function. */ private ObjectType typeOfThis; /** * The function node which this type represents. It may be {@code null}. */ private Node source; /** * The interfaces directly implemented by this function. * It is only relevant for constructors. May not be {@code null}. */ private List<ObjectType> implementedInterfaces = ImmutableList.of(); /** * The types which are subtypes of this function. It is only relevant for * constructors and may be {@code null}. */ private List<FunctionType> subTypes; /** * The template type name. May be {@code null}. */ private String templateTypeName; /** * Creates a function type. * @param registry the owner registry for this type

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>.kind = Kind.INTERFACE; this.typeOfThis = new InstanceObjectType(registry, this); } @Override public boolean isInstanceType() { // The universal constructor is its own instance, bizarrely. return equals(registry.getNativeType(U2U_CONSTRUCTOR_TYPE)); } @Override public boolean isConstructor() { return kind == Kind.CONSTRUCTOR; } @Override public boolean isInterface() { return kind == Kind.INTERFACE; } @Override public boolean isOrdinaryFunction() { return kind == Kind.ORDINARY; } @Override public boolean isFunctionType() { return true; } @Override public boolean canBeCalled() { return true; } public Iterable<Node> getParameters() { Node n = getParametersNode(); if (n != null) { return n.children(); } else { return Collections.emptySet(); } } /** Gets an LP node that contains all params. May be null. */ public Node getParametersNode() { return call == null ? null : call.parameters; } /** Gets the minimum number of arguments that this function requires. */ public int getMinArguments() { // NOTE(nicksantos): There are some native functions that have optional // parameters before required parameters. This algorithm finds the position // of the last required parameter. int i = 0; int min = 0; for (Node n : getParameters()) { i++; if (!n.isOptionalArg() && !n.isVarArgs()) { min = i; } } return min; } /** * Gets the maximum number of arguments that this function requires, * or Integer.MAX_VALUE if this is a variable argument function. */ public int getMaxArguments() { Node params = getParametersNode(); if (params != null) { Node lastParam = params.getLastChild(); if (lastParam == null || !lastParam.isVarArgs()) { return params.getChildCount(); } } return Integer.MAX_VALUE; } public JSType getReturnType() { return call == null ? null : call.returnType; } /** * Gets the {@code prototype}

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> property of this function type. This is * equivalent to {@code (ObjectType) getPropertyType("prototype")}. */ public FunctionPrototypeType getPrototype() { // lazy initialization of the prototype field if (prototype == null) { setPrototype(new FunctionPrototypeType(registry, this, null)); } return prototype; } /** * Sets the prototype, creating the prototype object from the given * base type. * @param baseType The base type. */ public void setPrototypeBasedOn(ObjectType baseType) { if (prototype == null) { setPrototype( new FunctionPrototypeType( registry, this, baseType, isNativeObjectType())); } else { prototype.setImplicitPrototype(baseType); } } /** * Sets the prototype. * @param prototype the prototype. If this value is {@code null} it will * silently be discarded. */ public boolean setPrototype(FunctionPrototypeType prototype) { if (prototype == null) { return false; } // getInstanceType fails if the function is not a constructor if (isConstructor() && prototype == getInstanceType()) { return false; } this.prototype = prototype; if (isConstructor() || isInterface()) { FunctionType superClass = getSuperClassConstructor(); if (superClass != null) { superClass.addSubType(this); } } return true; } /** * Returns all interfaces implemented by a class or its superclass and any * superclasses for any of those interfaces. If this is called before all * types are resolved, it may return an incomplete set. */ public Iterable<ObjectType> getAllImplementedInterfaces() { Set<ObjectType> interfaces = Sets.newHashSet(); for (ObjectType type : getImplementedInterfaces()) { addRelatedInterfaces(type, interfaces); } return interfaces; } private void addRelatedInterfaces(ObjectType instance, Set<ObjectType> set) { FunctionType constructor = instance.getConstructor(); if (constructor != null) { if (!constructor.isInterface()) { return; } set.add(instance); if (constructor.getSuperClassConstructor() != null) { addRelatedInterfaces( constructor.getSuperClassConstructor().getInstanceType(), set); } } } /** Returns interfaces

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> implemented directly by a class or its superclass. */ public Iterable<ObjectType> getImplementedInterfaces() { FunctionType superCtor = isConstructor() ? getSuperClassConstructor() : null; if (superCtor == null) { return implementedInterfaces; } else { return Iterables.concat( implementedInterfaces, superCtor.getImplementedInterfaces()); } } public void setImplementedInterfaces(List<ObjectType> implementedInterfaces) { // Records this type for each implemented interface. for (ObjectType type : implementedInterfaces) { registry.registerTypeImplementingInterface(this, type); } this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces); } @Override public boolean hasProperty(String name) { return super.hasProperty(name) || "prototype".equals(name); } @Override public boolean hasOwnProperty(String name) { return super.hasOwnProperty(name) || "prototype".equals(name); } @Override public JSType getPropertyType(String name) { if ("prototype".equals(name)) { return getPrototype(); } else { if (!hasOwnProperty(name)) { if ("call".equals(name)) { // Define the "call" function lazily. Node params = getParametersNode(); if (params == null) { // If there's no params array, don't do any type-checking // in this CALL function. defineDeclaredProperty(name, new FunctionType(registry, null, null, null, getReturnType()), false); } else { params = params.cloneTree(); Node thisTypeNode = Node.newString(Token.NAME, "thisType"); thisTypeNode.setJSType( registry.createOptionalNullableType(getTypeOfThis())); params.addChildToFront(thisTypeNode); thisTypeNode.setOptionalArg(true); defineDeclaredProperty(name, new FunctionType(registry, null, null, params, getReturnType()), false); } } else if ("apply".equals(name)) { // Define the "apply" function lazily. FunctionParamBuilder builder = new FunctionParamBuilder(registry); // Ecma-262 says that apply's second argument must be an Array // or an arguments object. We don't model the arguments object

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>, // so let's just be forgiving for now. // TODO(nicksantos): Model the Arguments object. builder.addOptionalParams( registry.createNullableType(getTypeOfThis()), registry.createNullableType( registry.getNativeType(JSTypeNative.OBJECT_TYPE))); defineDeclaredProperty(name, new FunctionType(registry, null, null, builder.build(), getReturnType()), false); } } return super.getPropertyType(name); } } @Override boolean defineProperty(String name, JSType type, boolean inferred, boolean inExterns) { if ("prototype".equals(name)) { ObjectType objType = type.toObjectType(); if (objType != null) { if (objType.equals(prototype)) { return true; } return setPrototype( new FunctionPrototypeType( registry, this, objType, isNativeObjectType())); } else { return false; } } return super.defineProperty(name, type, inferred, inExterns); } @Override public boolean isPropertyTypeInferred(String property) { return "prototype".equals(property) || super.isPropertyTypeInferred(property); } @Override public JSType getLeastSupertype(JSType that) { // NOTE(nicksantos): When we remove the unknown type, the function types // form a lattice with the universal constructor at the top of the lattice, // and the NoObject type at the bottom of the lattice. // // When we introduce the unknown type, it's much more difficult to make // heads or tails of the partial ordering of types, because there's no // clear hierarchy between the different components (parameter types and // return types) in the ArrowType. // // Rather than make the situation more complicated by introducing new // types (like unions of functions), we just fallback on the simpler // approach of using the universal constructor and the AnyObject as // the supremum and infinum of all function types. if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS>); if (functionInstance.equals(that)) { return that; } else if (functionInstance.equals(this)) { return this; } return registry.getNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE); } return super.getLeastSupertype(that); } @Override public JSType getGreatestSubtype(JSType that) { if (isFunctionType() && that.isFunctionType()) { if (equals(that)) { return this; } JSType functionInstance = registry.getNativeType( JSTypeNative.FUNCTION_INSTANCE_TYPE); if (functionInstance.equals(that)) { return this; } else if (functionInstance.equals(this)) { return that; } return registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE); } return super.getGreatestSubtype(that); } /** * Given a constructor or an interface type, get its superclass constructor * or {@code null} if none exists. */ public FunctionType getSuperClassConstructor() { Preconditions.checkArgument(isConstructor() || isInterface()); ObjectType maybeSuperInstanceType = getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return null; } return maybeSuperInstanceType.getConstructor(); } /** * Given a constructor or an interface type, find out whether the unknown * type is a supertype of the current type. */ public boolean hasUnknownSupertype() { Preconditions.checkArgument(isConstructor() || isInterface()); Preconditions.checkArgument(!this.isUnknownType()); // Potential infinite loop if our type system messes up or someone defines // a bad type. Otherwise the loop should always end. FunctionType ctor = this; while (true) { ObjectType maybeSuperInstanceType = ctor.getPrototype().getImplicitPrototype(); if (maybeSuperInstanceType == null) { return false; } if (maybeSuperInstanceType.isUnknownType()) { return true; } ctor = maybeSuperInstanceType.getConstructor(); if (ctor == null) { return false; } Preconditions.checkState(ctor.isConstructor() || ctor.isInterface()); } } /**

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * Given a constructor or an interface type and a property, finds the * top-most superclass that has the property defined (including this * constructor). */ public JSType getTopMostDefiningType(String propertyName) { Preconditions.checkState(isConstructor() || isInterface()); Preconditions.checkArgument(getPrototype().hasProperty(propertyName)); FunctionType ctor = this; JSType topInstanceType; do { topInstanceType = ctor.getInstanceType(); ctor = ctor.getSuperClassConstructor(); } while (ctor != null && ctor.getPrototype().hasProperty(propertyName)); return topInstanceType; } /** * Two function types are equal if their signatures match. Since they don't * have signatures, two interfaces are equal if their names match. */ @Override public boolean equals(Object otherType) { if (!(otherType instanceof FunctionType)) { return false; } FunctionType that = (FunctionType) otherType; if (!that.isFunctionType()) { return false; } if (this.isConstructor()) { if (that.isConstructor()) { return this == that; } return false; } if (this.isInterface()) { if (that.isInterface()) { return this.getReferenceName().equals(that.getReferenceName()); } return false; } if (that.isInterface()) { return false; } return this.typeOfThis.equals(that.typeOfThis) && this.call.equals(that.call); } @Override public int hashCode() { return isInterface() ? getReferenceName().hashCode() : call.hashCode(); } public boolean hasEqualCallType(FunctionType otherType) { return this.call.equals(otherType.call); } /** * Informally, a function is represented by * {@code function (params): returnType} where the {@code params} is a comma * separated list of types, the first one being a special * {@code this:T} if the function expects a known type for {@code this}. */ @Override public String toString() { if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) { return "Function"; } StringBuilder b =

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> new StringBuilder(32); b.append("function ("); int paramNum = (call == null || call.parameters == null) ? 0 : call.parameters.getChildCount(); boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType(); if (hasKnownTypeOfThis) { b.append("this:"); b.append(typeOfThis.toString()); } if (paramNum > 0) { if (hasKnownTypeOfThis) { b.append(", "); } Node p = call.parameters.getFirstChild(); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); while (p != null) { b.append(", "); if (p.isVarArgs()) { appendVarArgsString(b, p.getJSType()); } else { b.append(p.getJSType().toString()); } p = p.getNext(); } } b.append(")"); if (call != null && call.returnType != null) { b.append(": "); b.append(call.returnType); } return b.toString(); } /** Gets the string representation of a var args param. */ private void appendVarArgsString(StringBuilder builder, JSType paramType) { if (paramType.isUnionType()) { // Remove the optionalness from the var arg. paramType = ((UnionType) paramType).getRestrictedUnion( registry.getNativeType(JSTypeNative.VOID_TYPE)); } builder.append("...[").append(paramType.toString()).append("]"); } /** * A function is a subtype of another if their call methods are related via * subtyping and {@code this} is a subtype of {@code that} with regard to * the prototype chain. */ @Override public boolean isSubtype(JSType that) { if (this.equals(that)) { return true; } if (that.isFunctionType()) { if (((FunctionType) that).isInterface()) { // Any function can be assigned to an interface function. return true; } if (this

Closure, 137

<FILEB>
<CHANGES>
import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
<CHANGEE>
<CHANGES>
public static final String ARGUMENTS = "arguments";
<CHANGEE>
<CHANGES>
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
<CHANGEE>
<CHANGES>
private Set<String> referencedNames = ImmutableSet.of();
<CHANGEE>
<CHANGES>
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
<CHANGEE>
<CHANGES>
private Map<String, List<Node>> nameMap = Maps.newHashMap();
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
public void enterScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
referenceStack.push(referencedNames);
referencedNames = Sets.newHashSet();
<CHANGEE>
<CHANGES>
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
<CHANGEE>
<CHANGES>
for (Iterator<Var> it = t.getScope().getVars(); it.hasNext();) {
Var v = it.next();
handleScopeVar(v);
}
<CHANGEE>
<CHANGES>
Set<String> current = referencedNames;
referencedNames = referenceStack.pop();
<CHANGEE>
<CHANGES>
if (!referenceStack.isEmpty()) {
referencedNames.addAll(current);
}
}
<CHANGEE>
<CHANGES>
void handleScopeVar(Var v) {
String name = v.getName();
if (containsSeparator(name)) {
String newName = getOrginalName(name);
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(newName) &&
!referencedNames.contains(newName) &&
!newName.equals(ARGUMENTS)) {
referencedNames.remove(name);
<CHANGEE>
<CHANGES>
referencedNames.add(newName);
List<Node> references = nameMap.get(name);
Preconditions.checkState(references!= null);
for (Node n : references) {
Preconditions.checkState(n.getType() == Token.NAME);
n.setString(newName);
}
<CHANGEE>
<CHANGES>
nameMap.remove(name);
<CHANGEE>
<CHANGES>
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
<CHANGEE>
<CHANGES>
referencedNames.add(name);
<CHANGEE>
<CHANGES>
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
<CHANGEE>
<CHANGES>
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
<CHANGEE>
<CHANGES>
if (!name.equals(ARGUMENTS)) {
<CHANGEE>
<CHANGES>
}
declarations.put(name, newName);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(!name.equals(ARGUMENTS));
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
static boolean isReferenceName(Node n) {
return isName(n) &&!n.getString().isEmpty() &&!isLabelName(n);
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
<CHANGEE>
<CHANGES>
removeDuplicateDeclarations(root);
<CHANGEE>
<FILEE>
<FILEB> * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.javascript.jscomp; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multiset; import com.google.common.collect.Sets; <CHANGES> import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; <CHANGEE> import com.google.javascript.jscomp.Scope.Var; import com.google.javascript.rhino.Node; import com.google.javascript.rhino.Token; import com.google.javascript.rhino.TokenStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * Find all Functions, VARs, and Exception names and make them * unique. Specifically, it will not modify object properties. * @author johnlenz@google.com (John Lenz) * TODO(johnlenz): Try to merge this with the ScopeCreator. */ class MakeDeclaredNamesUnique implements NodeTraversal.ScopedCallback { <CHANGES> <CHANGEE> private Deque<Renamer> nameStack = new ArrayDeque<Renamer>(); private final Renamer rootRenamer; MakeDeclaredNamesUnique() { this.rootRenamer = new ContextualRenamer(); } MakeDeclaredNamesUnique(Renamer renamer) { this.rootRenamer = renamer; } static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) { return new Contextual<SCANS> * Gets the source node or null if this is an unknown function. */ public Node getSource() { return source; } /** * Sets the source node. */ public void setSource(Node source) { this.source = source; } /** Adds a type to the list of subtypes for this type. */ private void addSubType(FunctionType subType) { if (subTypes == null) { subTypes = Lists.newArrayList(); } subTypes.add(subType); } /** * Returns a list of types that are subtypes of this type. This is only valid * for constructor functions, and may be null. This allows a downward * traversal of the subtype graph. */ public List<FunctionType> getSubTypes() { return subTypes; } @Override public boolean hasCachedValues() { return prototype != null || super.hasCachedValues(); } /** * Gets the template type name. */ public String getTemplateTypeName() { return templateTypeName; } @Override JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) { call = (ArrowType) safeResolve(call, t, scope); prototype = (FunctionPrototypeType) safeResolve(prototype, t, scope); typeOfThis = (ObjectType) safeResolve(typeOfThis, t, scope); boolean changed = false; ImmutableList.Builder<ObjectType> resolvedInterfaces = ImmutableList.builder(); for (ObjectType iface : implementedInterfaces) { ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope); resolvedInterfaces.add(resolvedIface); changed |= (resolvedIface != iface); } if (changed) { implementedInterfaces = resolvedInterfaces.build(); } if (subTypes != null) { for (int i = 0; i < subTypes.size(); i++) { subTypes.set(i, (FunctionType) subTypes.get(i).resolve(t, scope)); } } return super.resolveInternal(t, scope); } }